zlib: add brotli support
Refs: https://github.com/nodejs/node/pull/20458 Co-authored-by: Hackzzila <admin@hackzzila.com> PR-URL: https://github.com/nodejs/node/pull/24938 Reviewed-By: Ruben Bridgewater <ruben@bridgewater.de> Reviewed-By: Matteo Collina <matteo.collina@gmail.com> Reviewed-By: Jan Krems <jan.krems@gmail.com> Reviewed-By: James M Snell <jasnell@gmail.com> Reviewed-By: Myles Borins <myles.borins@gmail.com> Reviewed-By: Ali Ijaz Sheikh <ofrobots@google.com> Reviewed-By: Daniel Bevenius <daniel.bevenius@gmail.com>
This commit is contained in:
parent
b857d713f5
commit
73753d4863
@ -624,6 +624,16 @@ An attempt was made to register something that is not a function as an
|
|||||||
The type of an asynchronous resource was invalid. Note that users are also able
|
The type of an asynchronous resource was invalid. Note that users are also able
|
||||||
to define their own types if using the public embedder API.
|
to define their own types if using the public embedder API.
|
||||||
|
|
||||||
|
<a id="ERR_BROTLI_INVALID_PARAM"></a>
|
||||||
|
### ERR_BROTLI_INVALID_PARAM
|
||||||
|
|
||||||
|
An invalid parameter key was passed during construction of a Brotli stream.
|
||||||
|
|
||||||
|
<a id="ERR_BROTLI_COMPRESSION_FAILED">
|
||||||
|
### ERR_BROTLI_COMPRESSION_FAILED
|
||||||
|
|
||||||
|
Data passed to a Brotli stream was not successfully compressed.
|
||||||
|
|
||||||
<a id="ERR_BUFFER_CONTEXT_NOT_AVAILABLE"></a>
|
<a id="ERR_BUFFER_CONTEXT_NOT_AVAILABLE"></a>
|
||||||
### ERR_BUFFER_CONTEXT_NOT_AVAILABLE
|
### ERR_BUFFER_CONTEXT_NOT_AVAILABLE
|
||||||
|
|
||||||
|
@ -546,6 +546,7 @@ E('ERR_ARG_NOT_ITERABLE', '%s must be iterable', TypeError);
|
|||||||
E('ERR_ASSERTION', '%s', Error);
|
E('ERR_ASSERTION', '%s', Error);
|
||||||
E('ERR_ASYNC_CALLBACK', '%s must be a function', TypeError);
|
E('ERR_ASYNC_CALLBACK', '%s must be a function', TypeError);
|
||||||
E('ERR_ASYNC_TYPE', 'Invalid name for async "type": %s', TypeError);
|
E('ERR_ASYNC_TYPE', 'Invalid name for async "type": %s', TypeError);
|
||||||
|
E('ERR_BROTLI_INVALID_PARAM', '%s is not a valid Brotli parameter', RangeError);
|
||||||
E('ERR_BUFFER_OUT_OF_BOUNDS',
|
E('ERR_BUFFER_OUT_OF_BOUNDS',
|
||||||
// Using a default argument here is important so the argument is not counted
|
// Using a default argument here is important so the argument is not counted
|
||||||
// towards `Function#length`.
|
// towards `Function#length`.
|
||||||
|
94
lib/zlib.js
94
lib/zlib.js
@ -22,10 +22,11 @@
|
|||||||
'use strict';
|
'use strict';
|
||||||
|
|
||||||
const {
|
const {
|
||||||
|
ERR_BROTLI_INVALID_PARAM,
|
||||||
ERR_BUFFER_TOO_LARGE,
|
ERR_BUFFER_TOO_LARGE,
|
||||||
ERR_INVALID_ARG_TYPE,
|
ERR_INVALID_ARG_TYPE,
|
||||||
ERR_OUT_OF_RANGE,
|
ERR_OUT_OF_RANGE,
|
||||||
ERR_ZLIB_INITIALIZATION_FAILED
|
ERR_ZLIB_INITIALIZATION_FAILED,
|
||||||
} = require('internal/errors').codes;
|
} = require('internal/errors').codes;
|
||||||
const Transform = require('_stream_transform');
|
const Transform = require('_stream_transform');
|
||||||
const {
|
const {
|
||||||
@ -45,11 +46,18 @@ const { owner_symbol } = require('internal/async_hooks').symbols;
|
|||||||
|
|
||||||
const constants = internalBinding('constants').zlib;
|
const constants = internalBinding('constants').zlib;
|
||||||
const {
|
const {
|
||||||
|
// Zlib flush levels
|
||||||
Z_NO_FLUSH, Z_BLOCK, Z_PARTIAL_FLUSH, Z_SYNC_FLUSH, Z_FULL_FLUSH, Z_FINISH,
|
Z_NO_FLUSH, Z_BLOCK, Z_PARTIAL_FLUSH, Z_SYNC_FLUSH, Z_FULL_FLUSH, Z_FINISH,
|
||||||
|
// Zlib option values
|
||||||
Z_MIN_CHUNK, Z_MIN_WINDOWBITS, Z_MAX_WINDOWBITS, Z_MIN_LEVEL, Z_MAX_LEVEL,
|
Z_MIN_CHUNK, Z_MIN_WINDOWBITS, Z_MAX_WINDOWBITS, Z_MIN_LEVEL, Z_MAX_LEVEL,
|
||||||
Z_MIN_MEMLEVEL, Z_MAX_MEMLEVEL, Z_DEFAULT_CHUNK, Z_DEFAULT_COMPRESSION,
|
Z_MIN_MEMLEVEL, Z_MAX_MEMLEVEL, Z_DEFAULT_CHUNK, Z_DEFAULT_COMPRESSION,
|
||||||
Z_DEFAULT_STRATEGY, Z_DEFAULT_WINDOWBITS, Z_DEFAULT_MEMLEVEL, Z_FIXED,
|
Z_DEFAULT_STRATEGY, Z_DEFAULT_WINDOWBITS, Z_DEFAULT_MEMLEVEL, Z_FIXED,
|
||||||
DEFLATE, DEFLATERAW, INFLATE, INFLATERAW, GZIP, GUNZIP, UNZIP
|
// Node's compression stream modes (node_zlib_mode)
|
||||||
|
DEFLATE, DEFLATERAW, INFLATE, INFLATERAW, GZIP, GUNZIP, UNZIP,
|
||||||
|
BROTLI_DECODE, BROTLI_ENCODE,
|
||||||
|
// Brotli operations (~flush levels)
|
||||||
|
BROTLI_OPERATION_PROCESS, BROTLI_OPERATION_FLUSH,
|
||||||
|
BROTLI_OPERATION_FINISH
|
||||||
} = constants;
|
} = constants;
|
||||||
|
|
||||||
// translation table for return codes.
|
// translation table for return codes.
|
||||||
@ -212,7 +220,7 @@ function ZlibBase(opts, mode, handle, { flush, finishFlush, fullFlush }) {
|
|||||||
// The ZlibBase class is not exported to user land, the mode should only be
|
// The ZlibBase class is not exported to user land, the mode should only be
|
||||||
// passed in by us.
|
// passed in by us.
|
||||||
assert(typeof mode === 'number');
|
assert(typeof mode === 'number');
|
||||||
assert(mode >= DEFLATE && mode <= UNZIP);
|
assert(mode >= DEFLATE && mode <= BROTLI_ENCODE);
|
||||||
|
|
||||||
if (opts) {
|
if (opts) {
|
||||||
chunkSize = opts.chunkSize;
|
chunkSize = opts.chunkSize;
|
||||||
@ -481,7 +489,7 @@ function processCallback() {
|
|||||||
// important to null out the values once they are no longer needed since
|
// important to null out the values once they are no longer needed since
|
||||||
// `_handle` can stay in memory long after the buffer is needed.
|
// `_handle` can stay in memory long after the buffer is needed.
|
||||||
var handle = this;
|
var handle = this;
|
||||||
var self = this.jsref;
|
var self = this[owner_symbol];
|
||||||
var state = self._writeState;
|
var state = self._writeState;
|
||||||
|
|
||||||
if (self._hadError) {
|
if (self._hadError) {
|
||||||
@ -622,6 +630,9 @@ function Zlib(opts, mode) {
|
|||||||
this._writeState,
|
this._writeState,
|
||||||
processCallback,
|
processCallback,
|
||||||
dictionary)) {
|
dictionary)) {
|
||||||
|
// TODO(addaleax): Sometimes we generate better error codes in C++ land,
|
||||||
|
// e.g. ERR_BROTLI_PARAM_SET_FAILED -- it's hard to access them with
|
||||||
|
// the current bindings setup, though.
|
||||||
throw new ERR_ZLIB_INITIALIZATION_FAILED();
|
throw new ERR_ZLIB_INITIALIZATION_FAILED();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -734,6 +745,70 @@ function createConvenienceMethod(ctor, sync) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const kMaxBrotliParam = Math.max(...Object.keys(constants).map((key) => {
|
||||||
|
return key.startsWith('BROTLI_PARAM_') ? constants[key] : 0;
|
||||||
|
}));
|
||||||
|
|
||||||
|
const brotliInitParamsArray = new Uint32Array(kMaxBrotliParam + 1);
|
||||||
|
|
||||||
|
const brotliDefaultOpts = {
|
||||||
|
flush: BROTLI_OPERATION_PROCESS,
|
||||||
|
finishFlush: BROTLI_OPERATION_FINISH,
|
||||||
|
fullFlush: BROTLI_OPERATION_FLUSH
|
||||||
|
};
|
||||||
|
function Brotli(opts, mode) {
|
||||||
|
assert(mode === BROTLI_DECODE || mode === BROTLI_ENCODE);
|
||||||
|
|
||||||
|
brotliInitParamsArray.fill(-1);
|
||||||
|
if (opts && opts.params) {
|
||||||
|
for (const origKey of Object.keys(opts.params)) {
|
||||||
|
const key = +origKey;
|
||||||
|
if (Number.isNaN(key) || key < 0 || key > kMaxBrotliParam ||
|
||||||
|
(brotliInitParamsArray[key] | 0) !== -1) {
|
||||||
|
throw new ERR_BROTLI_INVALID_PARAM(origKey);
|
||||||
|
}
|
||||||
|
|
||||||
|
const value = opts.params[origKey];
|
||||||
|
if (typeof value !== 'number' && typeof value !== 'boolean') {
|
||||||
|
throw new ERR_INVALID_ARG_TYPE('options.params[key]',
|
||||||
|
'number', opts.params[origKey]);
|
||||||
|
}
|
||||||
|
brotliInitParamsArray[key] = value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const handle = mode === BROTLI_DECODE ?
|
||||||
|
new binding.BrotliDecoder(mode) : new binding.BrotliEncoder(mode);
|
||||||
|
|
||||||
|
this._writeState = new Uint32Array(2);
|
||||||
|
if (!handle.init(brotliInitParamsArray,
|
||||||
|
this._writeState,
|
||||||
|
processCallback)) {
|
||||||
|
throw new ERR_ZLIB_INITIALIZATION_FAILED();
|
||||||
|
}
|
||||||
|
|
||||||
|
ZlibBase.call(this, opts, mode, handle, brotliDefaultOpts);
|
||||||
|
}
|
||||||
|
Object.setPrototypeOf(Brotli.prototype, Zlib.prototype);
|
||||||
|
Object.setPrototypeOf(Brotli, Zlib);
|
||||||
|
|
||||||
|
function BrotliCompress(opts) {
|
||||||
|
if (!(this instanceof BrotliCompress))
|
||||||
|
return new BrotliCompress(opts);
|
||||||
|
Brotli.call(this, opts, BROTLI_ENCODE);
|
||||||
|
}
|
||||||
|
Object.setPrototypeOf(BrotliCompress.prototype, Brotli.prototype);
|
||||||
|
Object.setPrototypeOf(BrotliCompress, Brotli);
|
||||||
|
|
||||||
|
function BrotliDecompress(opts) {
|
||||||
|
if (!(this instanceof BrotliDecompress))
|
||||||
|
return new BrotliDecompress(opts);
|
||||||
|
Brotli.call(this, opts, BROTLI_DECODE);
|
||||||
|
}
|
||||||
|
Object.setPrototypeOf(BrotliDecompress.prototype, Brotli.prototype);
|
||||||
|
Object.setPrototypeOf(BrotliDecompress, Brotli);
|
||||||
|
|
||||||
|
|
||||||
function createProperty(ctor) {
|
function createProperty(ctor) {
|
||||||
return {
|
return {
|
||||||
configurable: true,
|
configurable: true,
|
||||||
@ -759,6 +834,8 @@ module.exports = {
|
|||||||
DeflateRaw,
|
DeflateRaw,
|
||||||
InflateRaw,
|
InflateRaw,
|
||||||
Unzip,
|
Unzip,
|
||||||
|
BrotliCompress,
|
||||||
|
BrotliDecompress,
|
||||||
|
|
||||||
// Convenience methods.
|
// Convenience methods.
|
||||||
// compress/decompress a string or buffer in one step.
|
// compress/decompress a string or buffer in one step.
|
||||||
@ -775,7 +852,11 @@ module.exports = {
|
|||||||
gunzip: createConvenienceMethod(Gunzip, false),
|
gunzip: createConvenienceMethod(Gunzip, false),
|
||||||
gunzipSync: createConvenienceMethod(Gunzip, true),
|
gunzipSync: createConvenienceMethod(Gunzip, true),
|
||||||
inflateRaw: createConvenienceMethod(InflateRaw, false),
|
inflateRaw: createConvenienceMethod(InflateRaw, false),
|
||||||
inflateRawSync: createConvenienceMethod(InflateRaw, true)
|
inflateRawSync: createConvenienceMethod(InflateRaw, true),
|
||||||
|
brotliCompress: createConvenienceMethod(BrotliCompress, false),
|
||||||
|
brotliCompressSync: createConvenienceMethod(BrotliCompress, true),
|
||||||
|
brotliDecompress: createConvenienceMethod(BrotliDecompress, false),
|
||||||
|
brotliDecompressSync: createConvenienceMethod(BrotliDecompress, true),
|
||||||
};
|
};
|
||||||
|
|
||||||
Object.defineProperties(module.exports, {
|
Object.defineProperties(module.exports, {
|
||||||
@ -786,6 +867,8 @@ Object.defineProperties(module.exports, {
|
|||||||
createGzip: createProperty(Gzip),
|
createGzip: createProperty(Gzip),
|
||||||
createGunzip: createProperty(Gunzip),
|
createGunzip: createProperty(Gunzip),
|
||||||
createUnzip: createProperty(Unzip),
|
createUnzip: createProperty(Unzip),
|
||||||
|
createBrotliCompress: createProperty(BrotliCompress),
|
||||||
|
createBrotliDecompress: createProperty(BrotliDecompress),
|
||||||
constants: {
|
constants: {
|
||||||
configurable: false,
|
configurable: false,
|
||||||
enumerable: true,
|
enumerable: true,
|
||||||
@ -803,6 +886,7 @@ Object.defineProperties(module.exports, {
|
|||||||
const bkeys = Object.keys(constants);
|
const bkeys = Object.keys(constants);
|
||||||
for (var bk = 0; bk < bkeys.length; bk++) {
|
for (var bk = 0; bk < bkeys.length; bk++) {
|
||||||
var bkey = bkeys[bk];
|
var bkey = bkeys[bk];
|
||||||
|
if (bkey.startsWith('BROTLI')) continue;
|
||||||
Object.defineProperty(module.exports, bkey, {
|
Object.defineProperty(module.exports, bkey, {
|
||||||
enumerable: false, value: constants[bkey], writable: false
|
enumerable: false, value: constants[bkey], writable: false
|
||||||
});
|
});
|
||||||
|
1
node.gyp
1
node.gyp
@ -11,6 +11,7 @@
|
|||||||
'node_shared%': 'false',
|
'node_shared%': 'false',
|
||||||
'force_dynamic_crt%': 0,
|
'force_dynamic_crt%': 0,
|
||||||
'node_module_version%': '',
|
'node_module_version%': '',
|
||||||
|
'node_shared_brotli%': 'false',
|
||||||
'node_shared_zlib%': 'false',
|
'node_shared_zlib%': 'false',
|
||||||
'node_shared_http_parser%': 'false',
|
'node_shared_http_parser%': 'false',
|
||||||
'node_shared_cares%': 'false',
|
'node_shared_cares%': 'false',
|
||||||
|
@ -208,6 +208,10 @@
|
|||||||
'dependencies': [ 'deps/nghttp2/nghttp2.gyp:nghttp2' ],
|
'dependencies': [ 'deps/nghttp2/nghttp2.gyp:nghttp2' ],
|
||||||
}],
|
}],
|
||||||
|
|
||||||
|
[ 'node_shared_brotli=="false"', {
|
||||||
|
'dependencies': [ 'deps/brotli/brotli.gyp:brotli' ],
|
||||||
|
}],
|
||||||
|
|
||||||
[ 'OS=="mac"', {
|
[ 'OS=="mac"', {
|
||||||
# linking Corefoundation is needed since certain OSX debugging tools
|
# linking Corefoundation is needed since certain OSX debugging tools
|
||||||
# like Instruments require it for some features
|
# like Instruments require it for some features
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
#include "node_metadata.h"
|
#include "node_metadata.h"
|
||||||
#include "ares.h"
|
#include "ares.h"
|
||||||
|
#include "brotli/encode.h"
|
||||||
#include "nghttp2/nghttp2ver.h"
|
#include "nghttp2/nghttp2ver.h"
|
||||||
#include "node.h"
|
#include "node.h"
|
||||||
#include "util.h"
|
#include "util.h"
|
||||||
@ -72,6 +73,13 @@ Metadata::Versions::Versions() {
|
|||||||
llhttp = per_process::llhttp_version;
|
llhttp = per_process::llhttp_version;
|
||||||
http_parser = per_process::http_parser_version;
|
http_parser = per_process::http_parser_version;
|
||||||
|
|
||||||
|
brotli =
|
||||||
|
std::to_string(BrotliEncoderVersion() >> 24) +
|
||||||
|
"." +
|
||||||
|
std::to_string((BrotliEncoderVersion() & 0xFFF000) >> 12) +
|
||||||
|
"." +
|
||||||
|
std::to_string(BrotliEncoderVersion() & 0xFFF);
|
||||||
|
|
||||||
#if HAVE_OPENSSL
|
#if HAVE_OPENSSL
|
||||||
openssl = GetOpenSSLVersion();
|
openssl = GetOpenSSLVersion();
|
||||||
#endif
|
#endif
|
||||||
|
@ -12,6 +12,7 @@ namespace node {
|
|||||||
V(v8) \
|
V(v8) \
|
||||||
V(uv) \
|
V(uv) \
|
||||||
V(zlib) \
|
V(zlib) \
|
||||||
|
V(brotli) \
|
||||||
V(ares) \
|
V(ares) \
|
||||||
V(modules) \
|
V(modules) \
|
||||||
V(nghttp2) \
|
V(nghttp2) \
|
||||||
|
463
src/node_zlib.cc
463
src/node_zlib.cc
@ -28,6 +28,9 @@
|
|||||||
#include "util-inl.h"
|
#include "util-inl.h"
|
||||||
|
|
||||||
#include "v8.h"
|
#include "v8.h"
|
||||||
|
|
||||||
|
#include "brotli/encode.h"
|
||||||
|
#include "brotli/decode.h"
|
||||||
#include "zlib.h"
|
#include "zlib.h"
|
||||||
|
|
||||||
#include <errno.h>
|
#include <errno.h>
|
||||||
@ -82,7 +85,9 @@ enum node_zlib_mode {
|
|||||||
GUNZIP,
|
GUNZIP,
|
||||||
DEFLATERAW,
|
DEFLATERAW,
|
||||||
INFLATERAW,
|
INFLATERAW,
|
||||||
UNZIP
|
UNZIP,
|
||||||
|
BROTLI_DECODE,
|
||||||
|
BROTLI_ENCODE
|
||||||
};
|
};
|
||||||
|
|
||||||
#define GZIP_HEADER_ID1 0x1f
|
#define GZIP_HEADER_ID1 0x1f
|
||||||
@ -111,13 +116,13 @@ class ZlibContext : public MemoryRetainer {
|
|||||||
void SetFlush(int flush);
|
void SetFlush(int flush);
|
||||||
void GetAfterWriteOffsets(uint32_t* avail_in, uint32_t* avail_out) const;
|
void GetAfterWriteOffsets(uint32_t* avail_in, uint32_t* avail_out) const;
|
||||||
CompressionError GetErrorInfo() const;
|
CompressionError GetErrorInfo() const;
|
||||||
|
inline void SetMode(node_zlib_mode mode) { mode_ = mode; }
|
||||||
|
CompressionError ResetStream();
|
||||||
|
|
||||||
// Zlib-specific:
|
// Zlib-specific:
|
||||||
CompressionError Init(int level, int window_bits, int mem_level, int strategy,
|
CompressionError Init(int level, int window_bits, int mem_level, int strategy,
|
||||||
std::vector<unsigned char>&& dictionary);
|
std::vector<unsigned char>&& dictionary);
|
||||||
inline void SetMode(node_zlib_mode mode) { mode_ = mode; }
|
|
||||||
void SetAllocationFunctions(alloc_func alloc, free_func free, void* opaque);
|
void SetAllocationFunctions(alloc_func alloc, free_func free, void* opaque);
|
||||||
CompressionError ResetStream();
|
|
||||||
CompressionError SetParams(int level, int strategy);
|
CompressionError SetParams(int level, int strategy);
|
||||||
|
|
||||||
SET_MEMORY_INFO_NAME(ZlibContext)
|
SET_MEMORY_INFO_NAME(ZlibContext)
|
||||||
@ -146,6 +151,77 @@ class ZlibContext : public MemoryRetainer {
|
|||||||
DISALLOW_COPY_AND_ASSIGN(ZlibContext);
|
DISALLOW_COPY_AND_ASSIGN(ZlibContext);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// Brotli has different data types for compression and decompression streams,
|
||||||
|
// so some of the specifics are implemented in more specific subclasses
|
||||||
|
class BrotliContext : public MemoryRetainer {
|
||||||
|
public:
|
||||||
|
BrotliContext() = default;
|
||||||
|
|
||||||
|
void SetBuffers(char* in, uint32_t in_len, char* out, uint32_t out_len);
|
||||||
|
void SetFlush(int flush);
|
||||||
|
void GetAfterWriteOffsets(uint32_t* avail_in, uint32_t* avail_out) const;
|
||||||
|
inline void SetMode(node_zlib_mode mode) { mode_ = mode; }
|
||||||
|
|
||||||
|
protected:
|
||||||
|
node_zlib_mode mode_ = NONE;
|
||||||
|
uint8_t* next_in_ = nullptr;
|
||||||
|
uint8_t* next_out_ = nullptr;
|
||||||
|
size_t avail_in_ = 0;
|
||||||
|
size_t avail_out_ = 0;
|
||||||
|
BrotliEncoderOperation flush_ = BROTLI_OPERATION_PROCESS;
|
||||||
|
// TODO(addaleax): These should not need to be stored here.
|
||||||
|
// This is currently only done this way to make implementing ResetStream()
|
||||||
|
// easier.
|
||||||
|
brotli_alloc_func alloc_ = nullptr;
|
||||||
|
brotli_free_func free_ = nullptr;
|
||||||
|
void* alloc_opaque_ = nullptr;
|
||||||
|
|
||||||
|
private:
|
||||||
|
DISALLOW_COPY_AND_ASSIGN(BrotliContext);
|
||||||
|
};
|
||||||
|
|
||||||
|
class BrotliEncoderContext final : public BrotliContext {
|
||||||
|
public:
|
||||||
|
void Close();
|
||||||
|
void DoThreadPoolWork();
|
||||||
|
CompressionError Init(brotli_alloc_func alloc,
|
||||||
|
brotli_free_func free,
|
||||||
|
void* opaque);
|
||||||
|
CompressionError ResetStream();
|
||||||
|
CompressionError SetParams(int key, uint32_t value);
|
||||||
|
CompressionError GetErrorInfo() const;
|
||||||
|
|
||||||
|
SET_MEMORY_INFO_NAME(BrotliEncoderContext)
|
||||||
|
SET_SELF_SIZE(BrotliEncoderContext)
|
||||||
|
SET_NO_MEMORY_INFO() // state_ is covered through allocation tracking.
|
||||||
|
|
||||||
|
private:
|
||||||
|
bool last_result_ = false;
|
||||||
|
DeleteFnPtr<BrotliEncoderState, BrotliEncoderDestroyInstance> state_;
|
||||||
|
};
|
||||||
|
|
||||||
|
class BrotliDecoderContext final : public BrotliContext {
|
||||||
|
public:
|
||||||
|
void Close();
|
||||||
|
void DoThreadPoolWork();
|
||||||
|
CompressionError Init(brotli_alloc_func alloc,
|
||||||
|
brotli_free_func free,
|
||||||
|
void* opaque);
|
||||||
|
CompressionError ResetStream();
|
||||||
|
CompressionError SetParams(int key, uint32_t value);
|
||||||
|
CompressionError GetErrorInfo() const;
|
||||||
|
|
||||||
|
SET_MEMORY_INFO_NAME(BrotliDecoderContext)
|
||||||
|
SET_SELF_SIZE(BrotliDecoderContext)
|
||||||
|
SET_NO_MEMORY_INFO() // state_ is covered through allocation tracking.
|
||||||
|
|
||||||
|
private:
|
||||||
|
BrotliDecoderResult last_result_ = BROTLI_DECODER_RESULT_SUCCESS;
|
||||||
|
BrotliDecoderErrorCode error_ = BROTLI_DECODER_NO_ERROR;
|
||||||
|
std::string error_string_;
|
||||||
|
DeleteFnPtr<BrotliDecoderState, BrotliDecoderDestroyInstance> state_;
|
||||||
|
};
|
||||||
|
|
||||||
template <typename CompressionContext>
|
template <typename CompressionContext>
|
||||||
class CompressionStream : public AsyncWrap, public ThreadPoolWork {
|
class CompressionStream : public AsyncWrap, public ThreadPoolWork {
|
||||||
public:
|
public:
|
||||||
@ -340,6 +416,16 @@ class CompressionStream : public AsyncWrap, public ThreadPoolWork {
|
|||||||
Close();
|
Close();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void Reset(const FunctionCallbackInfo<Value> &args) {
|
||||||
|
CompressionStream* wrap;
|
||||||
|
ASSIGN_OR_RETURN_UNWRAP(&wrap, args.Holder());
|
||||||
|
|
||||||
|
AllocScope alloc_scope(wrap);
|
||||||
|
const CompressionError err = wrap->context()->ResetStream();
|
||||||
|
if (err.IsError())
|
||||||
|
wrap->EmitError(err);
|
||||||
|
}
|
||||||
|
|
||||||
void MemoryInfo(MemoryTracker* tracker) const override {
|
void MemoryInfo(MemoryTracker* tracker) const override {
|
||||||
tracker->TrackField("compression context", ctx_);
|
tracker->TrackField("compression context", ctx_);
|
||||||
tracker->TrackFieldWithSize("zlib_memory",
|
tracker->TrackFieldWithSize("zlib_memory",
|
||||||
@ -362,14 +448,19 @@ class CompressionStream : public AsyncWrap, public ThreadPoolWork {
|
|||||||
// to V8; rather, we first store it as "unreported" memory in a separate
|
// to V8; rather, we first store it as "unreported" memory in a separate
|
||||||
// field and later report it back from the main thread.
|
// field and later report it back from the main thread.
|
||||||
static void* AllocForZlib(void* data, uInt items, uInt size) {
|
static void* AllocForZlib(void* data, uInt items, uInt size) {
|
||||||
CompressionStream* ctx = static_cast<CompressionStream*>(data);
|
|
||||||
size_t real_size =
|
size_t real_size =
|
||||||
MultiplyWithOverflowCheck(static_cast<size_t>(items),
|
MultiplyWithOverflowCheck(static_cast<size_t>(items),
|
||||||
static_cast<size_t>(size)) + sizeof(size_t);
|
static_cast<size_t>(size));
|
||||||
char* memory = UncheckedMalloc(real_size);
|
return AllocForBrotli(data, real_size);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void* AllocForBrotli(void* data, size_t size) {
|
||||||
|
size += sizeof(size_t);
|
||||||
|
CompressionStream* ctx = static_cast<CompressionStream*>(data);
|
||||||
|
char* memory = UncheckedMalloc(size);
|
||||||
if (UNLIKELY(memory == nullptr)) return nullptr;
|
if (UNLIKELY(memory == nullptr)) return nullptr;
|
||||||
*reinterpret_cast<size_t*>(memory) = real_size;
|
*reinterpret_cast<size_t*>(memory) = size;
|
||||||
ctx->unreported_allocations_.fetch_add(real_size,
|
ctx->unreported_allocations_.fetch_add(size,
|
||||||
std::memory_order_relaxed);
|
std::memory_order_relaxed);
|
||||||
return memory + sizeof(size_t);
|
return memory + sizeof(size_t);
|
||||||
}
|
}
|
||||||
@ -484,6 +575,7 @@ class ZlibStream : public CompressionStream<ZlibContext> {
|
|||||||
Local<ArrayBuffer> ab = array->Buffer();
|
Local<ArrayBuffer> ab = array->Buffer();
|
||||||
uint32_t* write_result = static_cast<uint32_t*>(ab->GetContents().Data());
|
uint32_t* write_result = static_cast<uint32_t*>(ab->GetContents().Data());
|
||||||
|
|
||||||
|
CHECK(args[5]->IsFunction());
|
||||||
Local<Function> write_js_callback = args[5].As<Function>();
|
Local<Function> write_js_callback = args[5].As<Function>();
|
||||||
|
|
||||||
std::vector<unsigned char> dictionary;
|
std::vector<unsigned char> dictionary;
|
||||||
@ -525,20 +617,88 @@ class ZlibStream : public CompressionStream<ZlibContext> {
|
|||||||
wrap->EmitError(err);
|
wrap->EmitError(err);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void Reset(const FunctionCallbackInfo<Value> &args) {
|
|
||||||
ZlibStream* wrap;
|
|
||||||
ASSIGN_OR_RETURN_UNWRAP(&wrap, args.Holder());
|
|
||||||
|
|
||||||
AllocScope alloc_scope(wrap);
|
|
||||||
const CompressionError err = wrap->context()->ResetStream();
|
|
||||||
if (err.IsError())
|
|
||||||
wrap->EmitError(err);
|
|
||||||
}
|
|
||||||
|
|
||||||
SET_MEMORY_INFO_NAME(ZlibStream)
|
SET_MEMORY_INFO_NAME(ZlibStream)
|
||||||
SET_SELF_SIZE(ZlibStream)
|
SET_SELF_SIZE(ZlibStream)
|
||||||
};
|
};
|
||||||
|
|
||||||
|
template <typename CompressionContext>
|
||||||
|
class BrotliCompressionStream : public CompressionStream<CompressionContext> {
|
||||||
|
public:
|
||||||
|
BrotliCompressionStream(Environment* env,
|
||||||
|
Local<Object> wrap,
|
||||||
|
node_zlib_mode mode)
|
||||||
|
: CompressionStream<CompressionContext>(env, wrap) {
|
||||||
|
context()->SetMode(mode);
|
||||||
|
}
|
||||||
|
|
||||||
|
inline CompressionContext* context() {
|
||||||
|
return this->CompressionStream<CompressionContext>::context();
|
||||||
|
}
|
||||||
|
typedef typename CompressionStream<CompressionContext>::AllocScope AllocScope;
|
||||||
|
|
||||||
|
static void New(const FunctionCallbackInfo<Value>& args) {
|
||||||
|
Environment* env = Environment::GetCurrent(args);
|
||||||
|
CHECK(args[0]->IsInt32());
|
||||||
|
node_zlib_mode mode =
|
||||||
|
static_cast<node_zlib_mode>(args[0].As<Int32>()->Value());
|
||||||
|
new BrotliCompressionStream(env, args.This(), mode);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void Init(const FunctionCallbackInfo<Value>& args) {
|
||||||
|
BrotliCompressionStream* wrap;
|
||||||
|
ASSIGN_OR_RETURN_UNWRAP(&wrap, args.Holder());
|
||||||
|
CHECK(args.Length() == 3 && "init(params, writeResult, writeCallback)");
|
||||||
|
|
||||||
|
CHECK(args[1]->IsUint32Array());
|
||||||
|
uint32_t* write_result = reinterpret_cast<uint32_t*>(Buffer::Data(args[1]));
|
||||||
|
|
||||||
|
CHECK(args[2]->IsFunction());
|
||||||
|
Local<Function> write_js_callback = args[2].As<Function>();
|
||||||
|
wrap->InitStream(write_result, write_js_callback);
|
||||||
|
|
||||||
|
AllocScope alloc_scope(wrap);
|
||||||
|
CompressionError err =
|
||||||
|
wrap->context()->Init(
|
||||||
|
CompressionStream<CompressionContext>::AllocForBrotli,
|
||||||
|
CompressionStream<CompressionContext>::FreeForZlib,
|
||||||
|
static_cast<CompressionStream<CompressionContext>*>(wrap));
|
||||||
|
if (err.IsError()) {
|
||||||
|
wrap->EmitError(err);
|
||||||
|
args.GetReturnValue().Set(false);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
CHECK(args[0]->IsUint32Array());
|
||||||
|
const uint32_t* data = reinterpret_cast<uint32_t*>(Buffer::Data(args[0]));
|
||||||
|
size_t len = args[0].As<Uint32Array>()->Length();
|
||||||
|
|
||||||
|
for (int i = 0; static_cast<size_t>(i) < len; i++) {
|
||||||
|
if (data[i] == static_cast<uint32_t>(-1))
|
||||||
|
continue;
|
||||||
|
err = wrap->context()->SetParams(i, data[i]);
|
||||||
|
if (err.IsError()) {
|
||||||
|
wrap->EmitError(err);
|
||||||
|
args.GetReturnValue().Set(false);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
args.GetReturnValue().Set(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void Params(const FunctionCallbackInfo<Value>& args) {
|
||||||
|
// Currently a no-op, and not accessed from JS land.
|
||||||
|
// At some point Brotli may support changing parameters on the fly,
|
||||||
|
// in which case we can implement this and a JS equivalent similar to
|
||||||
|
// the zlib Params() function.
|
||||||
|
}
|
||||||
|
|
||||||
|
SET_MEMORY_INFO_NAME(BrotliCompressionStream)
|
||||||
|
SET_SELF_SIZE(BrotliCompressionStream)
|
||||||
|
};
|
||||||
|
|
||||||
|
using BrotliEncoderStream = BrotliCompressionStream<BrotliEncoderContext>;
|
||||||
|
using BrotliDecoderStream = BrotliCompressionStream<BrotliDecoderContext>;
|
||||||
|
|
||||||
void ZlibContext::Close() {
|
void ZlibContext::Close() {
|
||||||
CHECK_LE(mode_, UNZIP);
|
CHECK_LE(mode_, UNZIP);
|
||||||
@ -876,29 +1036,194 @@ CompressionError ZlibContext::SetParams(int level, int strategy) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void BrotliContext::SetBuffers(char* in, uint32_t in_len,
|
||||||
|
char* out, uint32_t out_len) {
|
||||||
|
next_in_ = reinterpret_cast<uint8_t*>(in);
|
||||||
|
next_out_ = reinterpret_cast<uint8_t*>(out);
|
||||||
|
avail_in_ = in_len;
|
||||||
|
avail_out_ = out_len;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void BrotliContext::SetFlush(int flush) {
|
||||||
|
flush_ = static_cast<BrotliEncoderOperation>(flush);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void BrotliContext::GetAfterWriteOffsets(uint32_t* avail_in,
|
||||||
|
uint32_t* avail_out) const {
|
||||||
|
*avail_in = avail_in_;
|
||||||
|
*avail_out = avail_out_;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void BrotliEncoderContext::DoThreadPoolWork() {
|
||||||
|
CHECK_EQ(mode_, BROTLI_ENCODE);
|
||||||
|
CHECK(state_);
|
||||||
|
const uint8_t* next_in = next_in_;
|
||||||
|
last_result_ = BrotliEncoderCompressStream(state_.get(),
|
||||||
|
flush_,
|
||||||
|
&avail_in_,
|
||||||
|
&next_in,
|
||||||
|
&avail_out_,
|
||||||
|
&next_out_,
|
||||||
|
nullptr);
|
||||||
|
next_in_ += next_in - next_in_;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void BrotliEncoderContext::Close() {
|
||||||
|
state_.reset();
|
||||||
|
mode_ = NONE;
|
||||||
|
}
|
||||||
|
|
||||||
|
CompressionError BrotliEncoderContext::Init(brotli_alloc_func alloc,
|
||||||
|
brotli_free_func free,
|
||||||
|
void* opaque) {
|
||||||
|
alloc_ = alloc;
|
||||||
|
free_ = free;
|
||||||
|
alloc_opaque_ = opaque;
|
||||||
|
state_.reset(BrotliEncoderCreateInstance(alloc, free, opaque));
|
||||||
|
if (!state_) {
|
||||||
|
return CompressionError("Could not initialize Brotli instance",
|
||||||
|
"ERR_ZLIB_INITIALIZATION_FAILED",
|
||||||
|
-1);
|
||||||
|
} else {
|
||||||
|
return CompressionError {};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
CompressionError BrotliEncoderContext::ResetStream() {
|
||||||
|
return Init(alloc_, free_, alloc_opaque_);
|
||||||
|
}
|
||||||
|
|
||||||
|
CompressionError BrotliEncoderContext::SetParams(int key, uint32_t value) {
|
||||||
|
if (!BrotliEncoderSetParameter(state_.get(),
|
||||||
|
static_cast<BrotliEncoderParameter>(key),
|
||||||
|
value)) {
|
||||||
|
return CompressionError("Setting parameter failed",
|
||||||
|
"ERR_BROTLI_PARAM_SET_FAILED",
|
||||||
|
-1);
|
||||||
|
} else {
|
||||||
|
return CompressionError {};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
CompressionError BrotliEncoderContext::GetErrorInfo() const {
|
||||||
|
if (!last_result_) {
|
||||||
|
return CompressionError("Compression failed",
|
||||||
|
"ERR_BROTLI_COMPRESSION_FAILED",
|
||||||
|
-1);
|
||||||
|
} else {
|
||||||
|
return CompressionError {};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void BrotliDecoderContext::Close() {
|
||||||
|
state_.reset();
|
||||||
|
mode_ = NONE;
|
||||||
|
}
|
||||||
|
|
||||||
|
void BrotliDecoderContext::DoThreadPoolWork() {
|
||||||
|
CHECK_EQ(mode_, BROTLI_DECODE);
|
||||||
|
CHECK(state_);
|
||||||
|
const uint8_t* next_in = next_in_;
|
||||||
|
last_result_ = BrotliDecoderDecompressStream(state_.get(),
|
||||||
|
&avail_in_,
|
||||||
|
&next_in,
|
||||||
|
&avail_out_,
|
||||||
|
&next_out_,
|
||||||
|
nullptr);
|
||||||
|
next_in_ += next_in - next_in_;
|
||||||
|
if (last_result_ == BROTLI_DECODER_RESULT_ERROR) {
|
||||||
|
error_ = BrotliDecoderGetErrorCode(state_.get());
|
||||||
|
error_string_ = std::string("ERR_") + BrotliDecoderErrorString(error_);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
CompressionError BrotliDecoderContext::Init(brotli_alloc_func alloc,
|
||||||
|
brotli_free_func free,
|
||||||
|
void* opaque) {
|
||||||
|
alloc_ = alloc;
|
||||||
|
free_ = free;
|
||||||
|
alloc_opaque_ = opaque;
|
||||||
|
state_.reset(BrotliDecoderCreateInstance(alloc, free, opaque));
|
||||||
|
if (!state_) {
|
||||||
|
return CompressionError("Could not initialize Brotli instance",
|
||||||
|
"ERR_ZLIB_INITIALIZATION_FAILED",
|
||||||
|
-1);
|
||||||
|
} else {
|
||||||
|
return CompressionError {};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
CompressionError BrotliDecoderContext::ResetStream() {
|
||||||
|
return Init(alloc_, free_, alloc_opaque_);
|
||||||
|
}
|
||||||
|
|
||||||
|
CompressionError BrotliDecoderContext::SetParams(int key, uint32_t value) {
|
||||||
|
if (!BrotliDecoderSetParameter(state_.get(),
|
||||||
|
static_cast<BrotliDecoderParameter>(key),
|
||||||
|
value)) {
|
||||||
|
return CompressionError("Setting parameter failed",
|
||||||
|
"ERR_BROTLI_PARAM_SET_FAILED",
|
||||||
|
-1);
|
||||||
|
} else {
|
||||||
|
return CompressionError {};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
CompressionError BrotliDecoderContext::GetErrorInfo() const {
|
||||||
|
if (error_ != BROTLI_DECODER_NO_ERROR) {
|
||||||
|
return CompressionError("Decompression failed",
|
||||||
|
error_string_.c_str(),
|
||||||
|
static_cast<int>(error_));
|
||||||
|
} else if (flush_ == BROTLI_OPERATION_FINISH &&
|
||||||
|
last_result_ == BROTLI_DECODER_RESULT_NEEDS_MORE_INPUT) {
|
||||||
|
// Match zlib's behaviour, as brotli doesn't have its own code for this.
|
||||||
|
return CompressionError("unexpected end of file",
|
||||||
|
"Z_BUF_ERROR",
|
||||||
|
Z_BUF_ERROR);
|
||||||
|
} else {
|
||||||
|
return CompressionError {};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
template <typename Stream>
|
||||||
|
struct MakeClass {
|
||||||
|
static void Make(Environment* env, Local<Object> target, const char* name) {
|
||||||
|
Local<FunctionTemplate> z = env->NewFunctionTemplate(Stream::New);
|
||||||
|
|
||||||
|
z->InstanceTemplate()->SetInternalFieldCount(1);
|
||||||
|
z->Inherit(AsyncWrap::GetConstructorTemplate(env));
|
||||||
|
|
||||||
|
env->SetProtoMethod(z, "write", Stream::template Write<true>);
|
||||||
|
env->SetProtoMethod(z, "writeSync", Stream::template Write<false>);
|
||||||
|
env->SetProtoMethod(z, "close", Stream::Close);
|
||||||
|
|
||||||
|
env->SetProtoMethod(z, "init", Stream::Init);
|
||||||
|
env->SetProtoMethod(z, "params", Stream::Params);
|
||||||
|
env->SetProtoMethod(z, "reset", Stream::Reset);
|
||||||
|
|
||||||
|
Local<String> zlibString = OneByteString(env->isolate(), name);
|
||||||
|
z->SetClassName(zlibString);
|
||||||
|
target->Set(env->context(),
|
||||||
|
zlibString,
|
||||||
|
z->GetFunction(env->context()).ToLocalChecked()).FromJust();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
void Initialize(Local<Object> target,
|
void Initialize(Local<Object> target,
|
||||||
Local<Value> unused,
|
Local<Value> unused,
|
||||||
Local<Context> context,
|
Local<Context> context,
|
||||||
void* priv) {
|
void* priv) {
|
||||||
Environment* env = Environment::GetCurrent(context);
|
Environment* env = Environment::GetCurrent(context);
|
||||||
Local<FunctionTemplate> z = env->NewFunctionTemplate(ZlibStream::New);
|
|
||||||
|
|
||||||
z->InstanceTemplate()->SetInternalFieldCount(1);
|
MakeClass<ZlibStream>::Make(env, target, "Zlib");
|
||||||
z->Inherit(AsyncWrap::GetConstructorTemplate(env));
|
MakeClass<BrotliEncoderStream>::Make(env, target, "BrotliEncoder");
|
||||||
|
MakeClass<BrotliDecoderStream>::Make(env, target, "BrotliDecoder");
|
||||||
env->SetProtoMethod(z, "write", ZlibStream::Write<true>);
|
|
||||||
env->SetProtoMethod(z, "writeSync", ZlibStream::Write<false>);
|
|
||||||
env->SetProtoMethod(z, "close", ZlibStream::Close);
|
|
||||||
|
|
||||||
env->SetProtoMethod(z, "init", ZlibStream::Init);
|
|
||||||
env->SetProtoMethod(z, "params", ZlibStream::Params);
|
|
||||||
env->SetProtoMethod(z, "reset", ZlibStream::Reset);
|
|
||||||
|
|
||||||
Local<String> zlibString = FIXED_ONE_BYTE_STRING(env->isolate(), "Zlib");
|
|
||||||
z->SetClassName(zlibString);
|
|
||||||
target->Set(env->context(),
|
|
||||||
zlibString,
|
|
||||||
z->GetFunction(env->context()).ToLocalChecked()).FromJust();
|
|
||||||
|
|
||||||
target->Set(env->context(),
|
target->Set(env->context(),
|
||||||
FIXED_ONE_BYTE_STRING(env->isolate(), "ZLIB_VERSION"),
|
FIXED_ONE_BYTE_STRING(env->isolate(), "ZLIB_VERSION"),
|
||||||
@ -944,6 +1269,8 @@ void DefineZlibConstants(Local<Object> target) {
|
|||||||
NODE_DEFINE_CONSTANT(target, DEFLATERAW);
|
NODE_DEFINE_CONSTANT(target, DEFLATERAW);
|
||||||
NODE_DEFINE_CONSTANT(target, INFLATERAW);
|
NODE_DEFINE_CONSTANT(target, INFLATERAW);
|
||||||
NODE_DEFINE_CONSTANT(target, UNZIP);
|
NODE_DEFINE_CONSTANT(target, UNZIP);
|
||||||
|
NODE_DEFINE_CONSTANT(target, BROTLI_DECODE);
|
||||||
|
NODE_DEFINE_CONSTANT(target, BROTLI_ENCODE);
|
||||||
|
|
||||||
NODE_DEFINE_CONSTANT(target, Z_MIN_WINDOWBITS);
|
NODE_DEFINE_CONSTANT(target, Z_MIN_WINDOWBITS);
|
||||||
NODE_DEFINE_CONSTANT(target, Z_MAX_WINDOWBITS);
|
NODE_DEFINE_CONSTANT(target, Z_MAX_WINDOWBITS);
|
||||||
@ -957,6 +1284,72 @@ void DefineZlibConstants(Local<Object> target) {
|
|||||||
NODE_DEFINE_CONSTANT(target, Z_MIN_LEVEL);
|
NODE_DEFINE_CONSTANT(target, Z_MIN_LEVEL);
|
||||||
NODE_DEFINE_CONSTANT(target, Z_MAX_LEVEL);
|
NODE_DEFINE_CONSTANT(target, Z_MAX_LEVEL);
|
||||||
NODE_DEFINE_CONSTANT(target, Z_DEFAULT_LEVEL);
|
NODE_DEFINE_CONSTANT(target, Z_DEFAULT_LEVEL);
|
||||||
|
|
||||||
|
// Brotli constants
|
||||||
|
NODE_DEFINE_CONSTANT(target, BROTLI_OPERATION_PROCESS);
|
||||||
|
NODE_DEFINE_CONSTANT(target, BROTLI_OPERATION_FLUSH);
|
||||||
|
NODE_DEFINE_CONSTANT(target, BROTLI_OPERATION_FINISH);
|
||||||
|
NODE_DEFINE_CONSTANT(target, BROTLI_OPERATION_EMIT_METADATA);
|
||||||
|
NODE_DEFINE_CONSTANT(target, BROTLI_PARAM_MODE);
|
||||||
|
NODE_DEFINE_CONSTANT(target, BROTLI_MODE_GENERIC);
|
||||||
|
NODE_DEFINE_CONSTANT(target, BROTLI_MODE_TEXT);
|
||||||
|
NODE_DEFINE_CONSTANT(target, BROTLI_MODE_FONT);
|
||||||
|
NODE_DEFINE_CONSTANT(target, BROTLI_DEFAULT_MODE);
|
||||||
|
NODE_DEFINE_CONSTANT(target, BROTLI_PARAM_QUALITY);
|
||||||
|
NODE_DEFINE_CONSTANT(target, BROTLI_MIN_QUALITY);
|
||||||
|
NODE_DEFINE_CONSTANT(target, BROTLI_MAX_QUALITY);
|
||||||
|
NODE_DEFINE_CONSTANT(target, BROTLI_DEFAULT_QUALITY);
|
||||||
|
NODE_DEFINE_CONSTANT(target, BROTLI_PARAM_LGWIN);
|
||||||
|
NODE_DEFINE_CONSTANT(target, BROTLI_MIN_WINDOW_BITS);
|
||||||
|
NODE_DEFINE_CONSTANT(target, BROTLI_MAX_WINDOW_BITS);
|
||||||
|
NODE_DEFINE_CONSTANT(target, BROTLI_LARGE_MAX_WINDOW_BITS);
|
||||||
|
NODE_DEFINE_CONSTANT(target, BROTLI_DEFAULT_WINDOW);
|
||||||
|
NODE_DEFINE_CONSTANT(target, BROTLI_PARAM_LGBLOCK);
|
||||||
|
NODE_DEFINE_CONSTANT(target, BROTLI_MIN_INPUT_BLOCK_BITS);
|
||||||
|
NODE_DEFINE_CONSTANT(target, BROTLI_MAX_INPUT_BLOCK_BITS);
|
||||||
|
NODE_DEFINE_CONSTANT(target, BROTLI_PARAM_DISABLE_LITERAL_CONTEXT_MODELING);
|
||||||
|
NODE_DEFINE_CONSTANT(target, BROTLI_PARAM_SIZE_HINT);
|
||||||
|
NODE_DEFINE_CONSTANT(target, BROTLI_PARAM_LARGE_WINDOW);
|
||||||
|
NODE_DEFINE_CONSTANT(target, BROTLI_PARAM_NPOSTFIX);
|
||||||
|
NODE_DEFINE_CONSTANT(target, BROTLI_PARAM_NDIRECT);
|
||||||
|
NODE_DEFINE_CONSTANT(target, BROTLI_DECODER_RESULT_ERROR);
|
||||||
|
NODE_DEFINE_CONSTANT(target, BROTLI_DECODER_RESULT_SUCCESS);
|
||||||
|
NODE_DEFINE_CONSTANT(target, BROTLI_DECODER_RESULT_NEEDS_MORE_INPUT);
|
||||||
|
NODE_DEFINE_CONSTANT(target, BROTLI_DECODER_RESULT_NEEDS_MORE_OUTPUT);
|
||||||
|
NODE_DEFINE_CONSTANT(target,
|
||||||
|
BROTLI_DECODER_PARAM_DISABLE_RING_BUFFER_REALLOCATION);
|
||||||
|
NODE_DEFINE_CONSTANT(target, BROTLI_DECODER_PARAM_LARGE_WINDOW);
|
||||||
|
NODE_DEFINE_CONSTANT(target, BROTLI_DECODER_NO_ERROR);
|
||||||
|
NODE_DEFINE_CONSTANT(target, BROTLI_DECODER_SUCCESS);
|
||||||
|
NODE_DEFINE_CONSTANT(target, BROTLI_DECODER_NEEDS_MORE_INPUT);
|
||||||
|
NODE_DEFINE_CONSTANT(target, BROTLI_DECODER_NEEDS_MORE_OUTPUT);
|
||||||
|
NODE_DEFINE_CONSTANT(target, BROTLI_DECODER_ERROR_FORMAT_EXUBERANT_NIBBLE);
|
||||||
|
NODE_DEFINE_CONSTANT(target, BROTLI_DECODER_ERROR_FORMAT_RESERVED);
|
||||||
|
NODE_DEFINE_CONSTANT(target,
|
||||||
|
BROTLI_DECODER_ERROR_FORMAT_EXUBERANT_META_NIBBLE);
|
||||||
|
NODE_DEFINE_CONSTANT(target,
|
||||||
|
BROTLI_DECODER_ERROR_FORMAT_SIMPLE_HUFFMAN_ALPHABET);
|
||||||
|
NODE_DEFINE_CONSTANT(target, BROTLI_DECODER_ERROR_FORMAT_SIMPLE_HUFFMAN_SAME);
|
||||||
|
NODE_DEFINE_CONSTANT(target, BROTLI_DECODER_ERROR_FORMAT_CL_SPACE);
|
||||||
|
NODE_DEFINE_CONSTANT(target, BROTLI_DECODER_ERROR_FORMAT_HUFFMAN_SPACE);
|
||||||
|
NODE_DEFINE_CONSTANT(target, BROTLI_DECODER_ERROR_FORMAT_CONTEXT_MAP_REPEAT);
|
||||||
|
NODE_DEFINE_CONSTANT(target, BROTLI_DECODER_ERROR_FORMAT_BLOCK_LENGTH_1);
|
||||||
|
NODE_DEFINE_CONSTANT(target, BROTLI_DECODER_ERROR_FORMAT_BLOCK_LENGTH_2);
|
||||||
|
NODE_DEFINE_CONSTANT(target, BROTLI_DECODER_ERROR_FORMAT_TRANSFORM);
|
||||||
|
NODE_DEFINE_CONSTANT(target, BROTLI_DECODER_ERROR_FORMAT_DICTIONARY);
|
||||||
|
NODE_DEFINE_CONSTANT(target, BROTLI_DECODER_ERROR_FORMAT_WINDOW_BITS);
|
||||||
|
NODE_DEFINE_CONSTANT(target, BROTLI_DECODER_ERROR_FORMAT_PADDING_1);
|
||||||
|
NODE_DEFINE_CONSTANT(target, BROTLI_DECODER_ERROR_FORMAT_PADDING_2);
|
||||||
|
NODE_DEFINE_CONSTANT(target, BROTLI_DECODER_ERROR_FORMAT_DISTANCE);
|
||||||
|
NODE_DEFINE_CONSTANT(target, BROTLI_DECODER_ERROR_DICTIONARY_NOT_SET);
|
||||||
|
NODE_DEFINE_CONSTANT(target, BROTLI_DECODER_ERROR_INVALID_ARGUMENTS);
|
||||||
|
NODE_DEFINE_CONSTANT(target, BROTLI_DECODER_ERROR_ALLOC_CONTEXT_MODES);
|
||||||
|
NODE_DEFINE_CONSTANT(target, BROTLI_DECODER_ERROR_ALLOC_TREE_GROUPS);
|
||||||
|
NODE_DEFINE_CONSTANT(target, BROTLI_DECODER_ERROR_ALLOC_CONTEXT_MAP);
|
||||||
|
NODE_DEFINE_CONSTANT(target, BROTLI_DECODER_ERROR_ALLOC_RING_BUFFER_1);
|
||||||
|
NODE_DEFINE_CONSTANT(target, BROTLI_DECODER_ERROR_ALLOC_RING_BUFFER_2);
|
||||||
|
NODE_DEFINE_CONSTANT(target, BROTLI_DECODER_ERROR_ALLOC_BLOCK_TYPE_TREES);
|
||||||
|
NODE_DEFINE_CONSTANT(target, BROTLI_DECODER_ERROR_UNREACHABLE);
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace node
|
} // namespace node
|
||||||
|
@ -2,7 +2,7 @@
|
|||||||
const common = require('../common');
|
const common = require('../common');
|
||||||
const assert = require('assert');
|
const assert = require('assert');
|
||||||
|
|
||||||
const expected_keys = ['ares', 'modules', 'node',
|
const expected_keys = ['ares', 'brotli', 'modules', 'node',
|
||||||
'uv', 'v8', 'zlib', 'nghttp2', 'napi',
|
'uv', 'v8', 'zlib', 'nghttp2', 'napi',
|
||||||
'http_parser', 'llhttp'];
|
'http_parser', 'llhttp'];
|
||||||
|
|
||||||
@ -25,6 +25,7 @@ assert.deepStrictEqual(actual_keys, expected_keys);
|
|||||||
const commonTemplate = /^\d+\.\d+\.\d+(?:-.*)?$/;
|
const commonTemplate = /^\d+\.\d+\.\d+(?:-.*)?$/;
|
||||||
|
|
||||||
assert(commonTemplate.test(process.versions.ares));
|
assert(commonTemplate.test(process.versions.ares));
|
||||||
|
assert(commonTemplate.test(process.versions.brotli));
|
||||||
assert(commonTemplate.test(process.versions.llhttp));
|
assert(commonTemplate.test(process.versions.llhttp));
|
||||||
assert(commonTemplate.test(process.versions.http_parser));
|
assert(commonTemplate.test(process.versions.http_parser));
|
||||||
assert(commonTemplate.test(process.versions.node));
|
assert(commonTemplate.test(process.versions.node));
|
||||||
|
Loading…
x
Reference in New Issue
Block a user