// Copyright (c) 2017-2022 Cloudflare, Inc. // Licensed under the Apache 2.0 license found in the LICENSE file or at: // https://opensource.org/licenses/Apache-2.0 // Copyright Joyent and Node contributors. All rights reserved. MIT license. #pragma once #include #include #include #include #include #include #include #include #include #include // The following implementation is adapted from Node.js // and therefore follows Node.js style as opposed to kj style. // Latest implementation of Node.js zlib can be found at: // https://github.com/nodejs/node/blob/main/src/node_zlib.cc namespace workerd::api::node { #ifndef ZLIB_ERROR_CODES #define ZLIB_ERROR_CODES(V) \ V(Z_OK) \ V(Z_STREAM_END) \ V(Z_NEED_DICT) \ V(Z_ERRNO) \ V(Z_STREAM_ERROR) \ V(Z_DATA_ERROR) \ V(Z_MEM_ERROR) \ V(Z_BUF_ERROR) \ V(Z_VERSION_ERROR) inline const char* ZlibStrerror(int err) { #define V(code) \ if (err == code) return #code; ZLIB_ERROR_CODES(V) #undef V return "Z_UNKNOWN_ERROR"; } #endif // ZLIB_ERROR_CODES // Certain zlib constants are defined by Node.js itself static constexpr auto Z_MIN_CHUNK = 64; static constexpr auto Z_MAX_CHUNK = 128 * 1024 * 1024; static constexpr auto Z_DEFAULT_CHUNK = 16 * 1024; static constexpr auto Z_MIN_MEMLEVEL = 1; static constexpr auto Z_MAX_MEMLEVEL = 9; static constexpr auto Z_DEFAULT_MEMLEVEL = 8; static constexpr auto Z_MIN_LEVEL = -1; static constexpr auto Z_MAX_LEVEL = 9; static constexpr auto Z_DEFAULT_LEVEL = Z_DEFAULT_COMPRESSION; static constexpr auto Z_MIN_WINDOWBITS = 8; static constexpr auto Z_MAX_WINDOWBITS = 15; static constexpr auto Z_DEFAULT_WINDOWBITS = 15; static constexpr uint8_t GZIP_HEADER_ID1 = 0x1f; static constexpr uint8_t GZIP_HEADER_ID2 = 0x8b; using ZlibModeValue = uint8_t; enum class ZlibMode : ZlibModeValue { NONE, DEFLATE, INFLATE, GZIP, GUNZIP, DEFLATERAW, INFLATERAW, UNZIP, BROTLI_DECODE, BROTLI_ENCODE, ZSTD_ENCODE, ZSTD_DECODE }; // When possible, we intentionally override chunkSize to a value that is likely to perform better static constexpr auto ZLIB_PERFORMANT_CHUNK_SIZE = 40 * 1024; struct CompressionError { CompressionError(kj::StringPtr _message, kj::StringPtr _code, int _err) : message(kj::str(_message)), code(kj::str(_code)), err(_err) { JSG_REQUIRE(message.size() != 0, Error, "Compression error message should not be null"); } kj::String message; kj::String code; int err; }; class ZlibContext final { public: explicit ZlibContext(ZlibMode _mode): mode(_mode) {} ZlibContext() = default; ~ZlibContext() noexcept(false); KJ_DISALLOW_COPY_AND_MOVE(ZlibContext); void setBuffers(kj::ArrayPtr input, kj::ArrayPtr output); void setInputBuffer(kj::ArrayPtr input); void setOutputBuffer(kj::ArrayPtr output); // Clear all buffer pointers from z_stream to prevent stale pointer access. // Must be called after each write operation completes and results have been // captured, so that subsequent operations (e.g. deflateParams) cannot use // dangling pointers into freed backing stores. // // Note: zlib's deflate() rejects next_out == NULL with Z_STREAM_ERROR even // when avail_out == 0, so we point next_out at a valid dummy byte instead. // With avail_out == 0, no data will actually be written to it. void clearBuffers() { stream.next_in = nullptr; stream.avail_in = 0; stream.next_out = &dummyByte; stream.avail_out = 0; } int getFlush() const { return flush; }; void setFlush(int value) { flush = value; }; // Function signature is same as Node.js implementation. // Ref: https://github.com/nodejs/node/blob/9edf4a0856681a7665bd9dcf2ca7cac252784b98/src/node_zlib.cc#L880 void getAfterWriteResult(uint32_t* availIn, uint32_t* availOut) const { *availIn = stream.avail_in; *availOut = stream.avail_out; } void setMode(ZlibMode value) { mode = value; }; kj::Maybe resetStream(); kj::Maybe getError() const; void setAllocationFunctions(alloc_func alloc, free_func free, void* opaque) { stream.zalloc = alloc; stream.zfree = free; stream.opaque = opaque; } // Equivalent to Node.js' `DoThreadPoolWork` function. // Ref: https://github.com/nodejs/node/blob/9edf4a0856681a7665bd9dcf2ca7cac252784b98/src/node_zlib.cc#L760 void work(); // Returns true when the zlib stream has reached Z_STREAM_END, indicating // that all compressed data has been fully processed. bool isStreamEnd() const { return err == Z_STREAM_END; } uint getAvailIn() const { return stream.avail_in; }; void setAvailIn(uint value) { stream.avail_in = value; }; uint getAvailOut() const { return stream.avail_out; } void setAvailOut(uint value) { stream.avail_out = value; }; z_stream* getStream() { return &stream; } // Zlib void initialize(int _level, int _windowBits, int _memLevel, int _strategy, jsg::Optional> _dictionary); kj::Maybe setParams(int level, int strategy); struct Options { jsg::Optional flush; jsg::Optional finishFlush; jsg::Optional chunkSize; jsg::Optional windowBits; jsg::Optional level; jsg::Optional memLevel; jsg::Optional strategy; jsg::Optional> dictionary; jsg::Optional maxOutputLength; JSG_STRUCT(flush, finishFlush, chunkSize, windowBits, level, memLevel, strategy, dictionary, maxOutputLength); }; private: bool initializeZlib(); kj::Maybe setDictionary(); CompressionError constructError(kj::StringPtr message) const { if (stream.msg != nullptr) message = kj::StringPtr(stream.msg); return {kj::str(message), kj::str(ZlibStrerror(err)), err}; }; bool initialized = false; ZlibMode mode = ZlibMode::NONE; int flush = Z_NO_FLUSH; int windowBits = 0; int level = 0; int memLevel = 0; int strategy = 0; kj::Vector dictionary; int err = Z_OK; unsigned int gzip_id_bytes_read = 0; z_stream stream{}; // Dummy byte target for clearBuffers(). zlib's deflate() rejects // next_out == NULL even when avail_out == 0, so we need a valid address. Bytef dummyByte = 0; }; using CompressionStreamErrorHandler = jsg::Function; class BrotliContext { public: explicit BrotliContext(ZlibMode _mode): mode(_mode) {} KJ_DISALLOW_COPY(BrotliContext); void setBuffers(kj::ArrayPtr input, kj::ArrayPtr output); void setInputBuffer(kj::ArrayPtr input); void setOutputBuffer(kj::ArrayPtr output); void setFlush(int flush); kj::uint getAvailOut() const; void getAfterWriteResult(uint32_t* availIn, uint32_t* availOut) const; void setMode(ZlibMode _mode) { mode = _mode; } void clearBuffers() { nextIn = nullptr; nextOut = nullptr; availIn = 0; availOut = 0; } struct Options { jsg::Optional flush; jsg::Optional finishFlush; jsg::Optional chunkSize; jsg::Optional> params; jsg::Optional maxOutputLength; JSG_STRUCT(flush, finishFlush, chunkSize, params, maxOutputLength); }; protected: ZlibMode mode; const uint8_t* nextIn = nullptr; uint8_t* nextOut = nullptr; size_t availIn = 0; size_t availOut = 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_brotli = nullptr; brotli_free_func free_brotli = nullptr; void* alloc_opaque_brotli = nullptr; }; class BrotliEncoderContext final: public BrotliContext { public: static const ZlibMode Mode = ZlibMode::BROTLI_ENCODE; explicit BrotliEncoderContext(ZlibMode _mode); KJ_DISALLOW_COPY_AND_MOVE(BrotliEncoderContext); // Equivalent to Node.js' `DoThreadPoolWork` implementation. void work(); kj::Maybe initialize( brotli_alloc_func init_alloc_func, brotli_free_func init_free_func, void* init_opaque_func); kj::Maybe resetStream(); kj::Maybe setParams(int key, uint32_t value); kj::Maybe getError() const; bool isStreamEnd() const; private: bool lastResult = false; bool streamEnd = false; kj::Own state; }; class BrotliDecoderContext final: public BrotliContext { public: static const ZlibMode Mode = ZlibMode::BROTLI_DECODE; explicit BrotliDecoderContext(ZlibMode _mode); KJ_DISALLOW_COPY_AND_MOVE(BrotliDecoderContext); // Equivalent to Node.js' `DoThreadPoolWork` implementation. void work(); kj::Maybe initialize( brotli_alloc_func init_alloc_func, brotli_free_func init_free_func, void* init_opaque_func); kj::Maybe resetStream(); kj::Maybe setParams(int key, uint32_t value); kj::Maybe getError() const; bool isStreamEnd() const; private: BrotliDecoderResult lastResult = BROTLI_DECODER_RESULT_SUCCESS; BrotliDecoderErrorCode error = BROTLI_DECODER_NO_ERROR; kj::String errorString; kj::Own state; }; class ZstdContext { public: explicit ZstdContext(ZlibMode _mode): mode(_mode) {} KJ_DISALLOW_COPY(ZstdContext); void setBuffers(kj::ArrayPtr input, kj::ArrayPtr output); void setInputBuffer(kj::ArrayPtr input); void setOutputBuffer(kj::ArrayPtr output); void setFlush(int flush); kj::uint getAvailOut() const; void getAfterWriteResult(uint32_t* availIn, uint32_t* availOut) const; void setMode(ZlibMode _mode) { mode = _mode; } void clearBuffers() { input_ = {nullptr, 0, 0}; output_ = {nullptr, 0, 0}; } struct Options { jsg::Optional flush; jsg::Optional finishFlush; jsg::Optional chunkSize; jsg::Optional> params; jsg::Optional maxOutputLength; jsg::Optional pledgedSrcSize; JSG_STRUCT(flush, finishFlush, chunkSize, params, maxOutputLength, pledgedSrcSize); }; protected: ZlibMode mode; ZSTD_inBuffer input_{nullptr, 0, 0}; ZSTD_outBuffer output_{nullptr, 0, 0}; ZSTD_EndDirective flush_ = ZSTD_e_continue; }; class ZstdEncoderContext final: public ZstdContext { public: static const ZlibMode Mode = ZlibMode::ZSTD_ENCODE; explicit ZstdEncoderContext(ZlibMode _mode); KJ_DISALLOW_COPY_AND_MOVE(ZstdEncoderContext); void work(); kj::Maybe initialize(uint64_t pledgedSrcSize); kj::Maybe resetStream(); kj::Maybe setParams(int key, int value); kj::Maybe getError() const; bool isStreamEnd() const; private: size_t lastResult = 0; kj::Own cctx_; ZSTD_ErrorCode error_ = ZSTD_error_no_error; }; class ZstdDecoderContext final: public ZstdContext { public: static const ZlibMode Mode = ZlibMode::ZSTD_DECODE; explicit ZstdDecoderContext(ZlibMode _mode); KJ_DISALLOW_COPY_AND_MOVE(ZstdDecoderContext); void work(); kj::Maybe initialize(); kj::Maybe resetStream(); kj::Maybe setParams(int key, int value); kj::Maybe getError() const; bool isStreamEnd() const; private: size_t lastResult = 0; kj::Own dctx_; ZSTD_ErrorCode error_ = ZSTD_error_no_error; bool frameInProgress_ = false; }; // Implements utilities in support of the Node.js Zlib class ZlibUtil final: public jsg::Object { public: ZlibUtil() = default; ZlibUtil(jsg::Lock&, const jsg::Url&) {} template class CompressionStream: public jsg::Object { public: explicit CompressionStream( ZlibMode _mode, kj::Arc&& externalMemoryTarget) : allocator(kj::mv(externalMemoryTarget)), context_(_mode) {} // TODO(soon): Find a way to add noexcept(false) to this destructor. ~CompressionStream(); KJ_DISALLOW_COPY_AND_MOVE(CompressionStream); static jsg::Ref constructor(jsg::Lock& js, ZlibModeValue mode); void close(); bool checkError(jsg::Lock& js); void emitError(jsg::Lock& js, const CompressionError& error); template void writeStream( jsg::Lock& js, int flush, kj::ArrayPtr input, kj::ArrayPtr output); void setErrorHandler(CompressionStreamErrorHandler handler) { errorHandler = kj::mv(handler); } void updateWriteResult(jsg::Lock& js); template void write(jsg::Lock& js, int flush, jsg::Optional> input, uint32_t inputOffset, uint32_t inputLength, kj::Array output, uint32_t outputOffset, uint32_t outputLength); void reset(jsg::Lock& js); JSG_RESOURCE_TYPE(CompressionStream) { JSG_METHOD(close); JSG_METHOD_NAMED(write, template write); JSG_METHOD_NAMED(writeSync, template write); JSG_METHOD(reset); JSG_METHOD(setErrorHandler); } protected: CompressionContext* context() { return &context_; } void initializeStream( jsg::Lock& js, jsg::JsArrayBufferView& _write_result, jsg::Function writeCallback); // Used to store allocations in Brotli* operations. // This declaration should be physically positioned before // context to avoid `heap-use-after-free` ASan error. CompressionAllocator allocator; private: CompressionContext context_; bool initialized = false; bool writing = false; bool pending_close = false; bool closed = false; // Equivalent to `write_js_callback` in Node.js jsg::Optional> writeCallback; jsg::Optional> writeResult; jsg::Optional errorHandler; }; class ZlibStream final: public CompressionStream { public: explicit ZlibStream( ZlibMode mode, kj::Arc&& externalMemoryTarget) : CompressionStream(mode, kj::mv(externalMemoryTarget)) {} KJ_DISALLOW_COPY_AND_MOVE(ZlibStream); static jsg::Ref constructor(jsg::Lock& js, ZlibModeValue mode); // Instance methods void initialize(jsg::Lock& js, int windowBits, int level, int memLevel, int strategy, jsg::JsArrayBufferView writeState, jsg::Function writeCallback, jsg::Optional> dictionary); void params(jsg::Lock& js, int level, int strategy); JSG_RESOURCE_TYPE(ZlibStream) { JSG_INHERIT(CompressionStream); JSG_METHOD(initialize); JSG_METHOD(params); } }; template class BrotliCompressionStream: public CompressionStream { public: explicit BrotliCompressionStream( ZlibMode _mode, kj::Arc&& externalMemoryTarget) : CompressionStream(_mode, kj::mv(externalMemoryTarget)) {} KJ_DISALLOW_COPY_AND_MOVE(BrotliCompressionStream); static jsg::Ref constructor(jsg::Lock& js, ZlibModeValue mode); bool initialize(jsg::Lock& js, jsg::JsArrayBufferView params, jsg::JsArrayBufferView writeResult, jsg::Function writeCallback); void params() { // 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. } JSG_RESOURCE_TYPE(BrotliCompressionStream) { JSG_INHERIT(CompressionStream); JSG_METHOD(initialize); JSG_METHOD(params); } CompressionContext* context() { return this->CompressionStream::context(); } }; template class ZstdCompressionStream: public CompressionStream { public: explicit ZstdCompressionStream( ZlibMode _mode, kj::Arc&& externalMemoryTarget) : CompressionStream(_mode, kj::mv(externalMemoryTarget)) {} KJ_DISALLOW_COPY_AND_MOVE(ZstdCompressionStream); static jsg::Ref constructor(jsg::Lock& js, ZlibModeValue mode); bool initialize(jsg::Lock& js, jsg::JsArrayBufferView params, jsg::JsArrayBufferView writeResult, jsg::Function writeCallback, jsg::Optional pledgedSrcSize); void params() { // Currently a no-op, and not accessed from JS land. } JSG_RESOURCE_TYPE(ZstdCompressionStream) { JSG_INHERIT(CompressionStream); JSG_METHOD(initialize); JSG_METHOD(params); } CompressionContext* context() { return this->CompressionStream::context(); } }; using InputSource = kj::OneOf, kj::Array>; using CompressCallbackArg = kj::OneOf>; using CompressCallback = jsg::Function; uint32_t crc32Sync(InputSource data, uint32_t value); void zlibWithCallback(jsg::Lock& js, InputSource data, ZlibContext::Options options, ZlibModeValue mode, CompressCallback cb); kj::Array zlibSync( jsg::Lock& js, InputSource data, ZlibContext::Options options, ZlibModeValue mode); template kj::Array brotliSync(jsg::Lock& js, InputSource data, BrotliContext::Options options); template void brotliWithCallback( jsg::Lock& js, InputSource data, BrotliContext::Options options, CompressCallback cb); template kj::Array zstdSync(jsg::Lock& js, InputSource data, ZstdContext::Options options); template void zstdWithCallback( jsg::Lock& js, InputSource data, ZstdContext::Options options, CompressCallback cb); JSG_RESOURCE_TYPE(ZlibUtil) { JSG_METHOD_NAMED(crc32, crc32Sync); JSG_METHOD(zlibSync); JSG_METHOD_NAMED(zlib, zlibWithCallback); JSG_METHOD_NAMED(brotliDecompressSync, template brotliSync); JSG_METHOD_NAMED(brotliCompressSync, template brotliSync); JSG_METHOD_NAMED(brotliDecompress, template brotliWithCallback); JSG_METHOD_NAMED(brotliCompress, template brotliWithCallback); JSG_METHOD_NAMED(zstdDecompressSync, template zstdSync); JSG_METHOD_NAMED(zstdCompressSync, template zstdSync); JSG_METHOD_NAMED(zstdDecompress, template zstdWithCallback); JSG_METHOD_NAMED(zstdCompress, template zstdWithCallback); JSG_NESTED_TYPE(ZlibStream); JSG_NESTED_TYPE_NAMED(BrotliCompressionStream, BrotliEncoder); JSG_NESTED_TYPE_NAMED(BrotliCompressionStream, BrotliDecoder); JSG_NESTED_TYPE_NAMED(ZstdCompressionStream, ZstdEncoder); JSG_NESTED_TYPE_NAMED(ZstdCompressionStream, ZstdDecoder); // zlib.constants (part of the API contract for node:zlib) JSG_STATIC_CONSTANT_NAMED(CONST_Z_NO_FLUSH, Z_NO_FLUSH); JSG_STATIC_CONSTANT_NAMED(CONST_Z_PARTIAL_FLUSH, Z_PARTIAL_FLUSH); JSG_STATIC_CONSTANT_NAMED(CONST_Z_SYNC_FLUSH, Z_SYNC_FLUSH); JSG_STATIC_CONSTANT_NAMED(CONST_Z_FULL_FLUSH, Z_FULL_FLUSH); JSG_STATIC_CONSTANT_NAMED(CONST_Z_FINISH, Z_FINISH); JSG_STATIC_CONSTANT_NAMED(CONST_Z_BLOCK, Z_BLOCK); JSG_STATIC_CONSTANT_NAMED(CONST_Z_OK, Z_OK); JSG_STATIC_CONSTANT_NAMED(CONST_Z_STREAM_END, Z_STREAM_END); JSG_STATIC_CONSTANT_NAMED(CONST_Z_NEED_DICT, Z_NEED_DICT); JSG_STATIC_CONSTANT_NAMED(CONST_Z_ERRNO, Z_ERRNO); JSG_STATIC_CONSTANT_NAMED(CONST_Z_STREAM_ERROR, Z_STREAM_ERROR); JSG_STATIC_CONSTANT_NAMED(CONST_Z_DATA_ERROR, Z_DATA_ERROR); JSG_STATIC_CONSTANT_NAMED(CONST_Z_MEM_ERROR, Z_MEM_ERROR); JSG_STATIC_CONSTANT_NAMED(CONST_Z_BUF_ERROR, Z_BUF_ERROR); JSG_STATIC_CONSTANT_NAMED(CONST_Z_VERSION_ERROR, Z_VERSION_ERROR); JSG_STATIC_CONSTANT_NAMED(CONST_Z_NO_COMPRESSION, Z_NO_COMPRESSION); JSG_STATIC_CONSTANT_NAMED(CONST_Z_BEST_SPEED, Z_BEST_SPEED); JSG_STATIC_CONSTANT_NAMED(CONST_Z_BEST_COMPRESSION, Z_BEST_COMPRESSION); JSG_STATIC_CONSTANT_NAMED(CONST_Z_DEFAULT_COMPRESSION, Z_DEFAULT_COMPRESSION); JSG_STATIC_CONSTANT_NAMED(CONST_Z_FILTERED, Z_FILTERED); JSG_STATIC_CONSTANT_NAMED(CONST_Z_HUFFMAN_ONLY, Z_HUFFMAN_ONLY); JSG_STATIC_CONSTANT_NAMED(CONST_Z_RLE, Z_RLE); JSG_STATIC_CONSTANT_NAMED(CONST_Z_FIXED, Z_FIXED); JSG_STATIC_CONSTANT_NAMED(CONST_Z_DEFAULT_STRATEGY, Z_DEFAULT_STRATEGY); JSG_STATIC_CONSTANT_NAMED(CONST_ZLIB_VERNUM, ZLIB_VERNUM); JSG_STATIC_CONSTANT_NAMED(CONST_DEFLATE, static_cast(ZlibMode::DEFLATE)); JSG_STATIC_CONSTANT_NAMED(CONST_INFLATE, static_cast(ZlibMode::INFLATE)); JSG_STATIC_CONSTANT_NAMED(CONST_GZIP, static_cast(ZlibMode::GZIP)); JSG_STATIC_CONSTANT_NAMED(CONST_GUNZIP, static_cast(ZlibMode::GUNZIP)); JSG_STATIC_CONSTANT_NAMED(CONST_DEFLATERAW, static_cast(ZlibMode::DEFLATERAW)); JSG_STATIC_CONSTANT_NAMED(CONST_INFLATERAW, static_cast(ZlibMode::INFLATERAW)); JSG_STATIC_CONSTANT_NAMED(CONST_UNZIP, static_cast(ZlibMode::UNZIP)); JSG_STATIC_CONSTANT_NAMED( CONST_BROTLI_DECODE, static_cast(ZlibMode::BROTLI_DECODE)); JSG_STATIC_CONSTANT_NAMED( CONST_BROTLI_ENCODE, static_cast(ZlibMode::BROTLI_ENCODE)); JSG_STATIC_CONSTANT_NAMED(CONST_Z_MIN_WINDOWBITS, Z_MIN_WINDOWBITS); JSG_STATIC_CONSTANT_NAMED(CONST_Z_MAX_WINDOWBITS, Z_MAX_WINDOWBITS); JSG_STATIC_CONSTANT_NAMED(CONST_Z_DEFAULT_WINDOWBITS, Z_DEFAULT_WINDOWBITS); JSG_STATIC_CONSTANT_NAMED(CONST_Z_MIN_CHUNK, Z_MIN_CHUNK); JSG_STATIC_CONSTANT_NAMED(CONST_Z_MAX_CHUNK, Z_MAX_CHUNK); JSG_STATIC_CONSTANT_NAMED(CONST_Z_DEFAULT_CHUNK, Z_DEFAULT_CHUNK); JSG_STATIC_CONSTANT_NAMED(CONST_Z_MIN_MEMLEVEL, Z_MIN_MEMLEVEL); JSG_STATIC_CONSTANT_NAMED(CONST_Z_MAX_MEMLEVEL, Z_MAX_MEMLEVEL); JSG_STATIC_CONSTANT_NAMED(CONST_Z_DEFAULT_MEMLEVEL, Z_DEFAULT_MEMLEVEL); JSG_STATIC_CONSTANT_NAMED(CONST_Z_MIN_LEVEL, Z_MIN_LEVEL); JSG_STATIC_CONSTANT_NAMED(CONST_Z_MAX_LEVEL, Z_MAX_LEVEL); JSG_STATIC_CONSTANT_NAMED(CONST_Z_DEFAULT_LEVEL, Z_DEFAULT_LEVEL); JSG_STATIC_CONSTANT_NAMED(CONST_BROTLI_OPERATION_PROCESS, BROTLI_OPERATION_PROCESS); JSG_STATIC_CONSTANT_NAMED(CONST_BROTLI_OPERATION_FLUSH, BROTLI_OPERATION_FLUSH); JSG_STATIC_CONSTANT_NAMED(CONST_BROTLI_OPERATION_FINISH, BROTLI_OPERATION_FINISH); JSG_STATIC_CONSTANT_NAMED(CONST_BROTLI_OPERATION_EMIT_METADATA, BROTLI_OPERATION_EMIT_METADATA); JSG_STATIC_CONSTANT_NAMED(CONST_BROTLI_PARAM_MODE, BROTLI_PARAM_MODE); JSG_STATIC_CONSTANT_NAMED(CONST_BROTLI_MODE_GENERIC, BROTLI_MODE_GENERIC); JSG_STATIC_CONSTANT_NAMED(CONST_BROTLI_MODE_TEXT, BROTLI_MODE_TEXT); JSG_STATIC_CONSTANT_NAMED(CONST_BROTLI_MODE_FONT, BROTLI_MODE_FONT); JSG_STATIC_CONSTANT_NAMED(CONST_BROTLI_DEFAULT_MODE, BROTLI_DEFAULT_MODE); JSG_STATIC_CONSTANT_NAMED(CONST_BROTLI_PARAM_QUALITY, BROTLI_PARAM_QUALITY); JSG_STATIC_CONSTANT_NAMED(CONST_BROTLI_MIN_QUALITY, BROTLI_MIN_QUALITY); JSG_STATIC_CONSTANT_NAMED(CONST_BROTLI_MAX_QUALITY, BROTLI_MAX_QUALITY); JSG_STATIC_CONSTANT_NAMED(CONST_BROTLI_DEFAULT_QUALITY, BROTLI_DEFAULT_QUALITY); JSG_STATIC_CONSTANT_NAMED(CONST_BROTLI_PARAM_LGWIN, BROTLI_PARAM_LGWIN); JSG_STATIC_CONSTANT_NAMED(CONST_BROTLI_MIN_WINDOW_BITS, BROTLI_MIN_WINDOW_BITS); JSG_STATIC_CONSTANT_NAMED(CONST_BROTLI_MAX_WINDOW_BITS, BROTLI_MAX_WINDOW_BITS); JSG_STATIC_CONSTANT_NAMED(CONST_BROTLI_LARGE_MAX_WINDOW_BITS, BROTLI_LARGE_MAX_WINDOW_BITS); JSG_STATIC_CONSTANT_NAMED(CONST_BROTLI_DEFAULT_WINDOW, BROTLI_DEFAULT_WINDOW); JSG_STATIC_CONSTANT_NAMED(CONST_BROTLI_PARAM_LGBLOCK, BROTLI_PARAM_LGBLOCK); JSG_STATIC_CONSTANT_NAMED(CONST_BROTLI_MIN_INPUT_BLOCK_BITS, BROTLI_MIN_INPUT_BLOCK_BITS); JSG_STATIC_CONSTANT_NAMED(CONST_BROTLI_MAX_INPUT_BLOCK_BITS, BROTLI_MAX_INPUT_BLOCK_BITS); JSG_STATIC_CONSTANT_NAMED(CONST_BROTLI_PARAM_DISABLE_LITERAL_CONTEXT_MODELING, BROTLI_PARAM_DISABLE_LITERAL_CONTEXT_MODELING); JSG_STATIC_CONSTANT_NAMED(CONST_BROTLI_PARAM_SIZE_HINT, BROTLI_PARAM_SIZE_HINT); JSG_STATIC_CONSTANT_NAMED(CONST_BROTLI_PARAM_LARGE_WINDOW, BROTLI_PARAM_LARGE_WINDOW); JSG_STATIC_CONSTANT_NAMED(CONST_BROTLI_PARAM_NPOSTFIX, BROTLI_PARAM_NPOSTFIX); JSG_STATIC_CONSTANT_NAMED(CONST_BROTLI_PARAM_NDIRECT, BROTLI_PARAM_NDIRECT); JSG_STATIC_CONSTANT_NAMED(CONST_BROTLI_DECODER_RESULT_ERROR, BROTLI_DECODER_RESULT_ERROR); JSG_STATIC_CONSTANT_NAMED(CONST_BROTLI_DECODER_RESULT_SUCCESS, BROTLI_DECODER_RESULT_SUCCESS); JSG_STATIC_CONSTANT_NAMED( CONST_BROTLI_DECODER_RESULT_NEEDS_MORE_INPUT, BROTLI_DECODER_RESULT_NEEDS_MORE_INPUT); JSG_STATIC_CONSTANT_NAMED( CONST_BROTLI_DECODER_RESULT_NEEDS_MORE_OUTPUT, BROTLI_DECODER_RESULT_NEEDS_MORE_OUTPUT); JSG_STATIC_CONSTANT_NAMED(CONST_BROTLI_DECODER_PARAM_DISABLE_RING_BUFFER_REALLOCATION, BROTLI_DECODER_PARAM_DISABLE_RING_BUFFER_REALLOCATION); JSG_STATIC_CONSTANT_NAMED( CONST_BROTLI_DECODER_PARAM_LARGE_WINDOW, BROTLI_DECODER_PARAM_LARGE_WINDOW); JSG_STATIC_CONSTANT_NAMED(CONST_BROTLI_DECODER_NO_ERROR, BROTLI_DECODER_NO_ERROR); JSG_STATIC_CONSTANT_NAMED(CONST_BROTLI_DECODER_SUCCESS, BROTLI_DECODER_SUCCESS); JSG_STATIC_CONSTANT_NAMED( CONST_BROTLI_DECODER_NEEDS_MORE_INPUT, BROTLI_DECODER_NEEDS_MORE_INPUT); JSG_STATIC_CONSTANT_NAMED( CONST_BROTLI_DECODER_NEEDS_MORE_OUTPUT, BROTLI_DECODER_NEEDS_MORE_OUTPUT); JSG_STATIC_CONSTANT_NAMED(CONST_BROTLI_DECODER_ERROR_FORMAT_EXUBERANT_NIBBLE, BROTLI_DECODER_ERROR_FORMAT_EXUBERANT_NIBBLE); JSG_STATIC_CONSTANT_NAMED( CONST_BROTLI_DECODER_ERROR_FORMAT_RESERVED, BROTLI_DECODER_ERROR_FORMAT_RESERVED); JSG_STATIC_CONSTANT_NAMED(CONST_BROTLI_DECODER_ERROR_FORMAT_EXUBERANT_META_NIBBLE, BROTLI_DECODER_ERROR_FORMAT_EXUBERANT_META_NIBBLE); JSG_STATIC_CONSTANT_NAMED(CONST_BROTLI_DECODER_ERROR_FORMAT_SIMPLE_HUFFMAN_ALPHABET, BROTLI_DECODER_ERROR_FORMAT_SIMPLE_HUFFMAN_ALPHABET); JSG_STATIC_CONSTANT_NAMED(CONST_BROTLI_DECODER_ERROR_FORMAT_SIMPLE_HUFFMAN_SAME, BROTLI_DECODER_ERROR_FORMAT_SIMPLE_HUFFMAN_SAME); JSG_STATIC_CONSTANT_NAMED( CONST_BROTLI_DECODER_ERROR_FORMAT_CL_SPACE, BROTLI_DECODER_ERROR_FORMAT_CL_SPACE); JSG_STATIC_CONSTANT_NAMED( CONST_BROTLI_DECODER_ERROR_FORMAT_HUFFMAN_SPACE, BROTLI_DECODER_ERROR_FORMAT_HUFFMAN_SPACE); JSG_STATIC_CONSTANT_NAMED(CONST_BROTLI_DECODER_ERROR_FORMAT_CONTEXT_MAP_REPEAT, BROTLI_DECODER_ERROR_FORMAT_CONTEXT_MAP_REPEAT); JSG_STATIC_CONSTANT_NAMED(CONST_BROTLI_DECODER_ERROR_FORMAT_BLOCK_LENGTH_1, BROTLI_DECODER_ERROR_FORMAT_BLOCK_LENGTH_1); JSG_STATIC_CONSTANT_NAMED(CONST_BROTLI_DECODER_ERROR_FORMAT_BLOCK_LENGTH_2, BROTLI_DECODER_ERROR_FORMAT_BLOCK_LENGTH_2); JSG_STATIC_CONSTANT_NAMED( CONST_BROTLI_DECODER_ERROR_FORMAT_TRANSFORM, BROTLI_DECODER_ERROR_FORMAT_TRANSFORM); JSG_STATIC_CONSTANT_NAMED( CONST_BROTLI_DECODER_ERROR_FORMAT_DICTIONARY, BROTLI_DECODER_ERROR_FORMAT_DICTIONARY); JSG_STATIC_CONSTANT_NAMED( CONST_BROTLI_DECODER_ERROR_FORMAT_WINDOW_BITS, BROTLI_DECODER_ERROR_FORMAT_WINDOW_BITS); JSG_STATIC_CONSTANT_NAMED( CONST_BROTLI_DECODER_ERROR_FORMAT_PADDING_1, BROTLI_DECODER_ERROR_FORMAT_PADDING_1); JSG_STATIC_CONSTANT_NAMED( CONST_BROTLI_DECODER_ERROR_FORMAT_PADDING_2, BROTLI_DECODER_ERROR_FORMAT_PADDING_2); JSG_STATIC_CONSTANT_NAMED( CONST_BROTLI_DECODER_ERROR_FORMAT_DISTANCE, BROTLI_DECODER_ERROR_FORMAT_DISTANCE); JSG_STATIC_CONSTANT_NAMED( CONST_BROTLI_DECODER_ERROR_DICTIONARY_NOT_SET, BROTLI_DECODER_ERROR_DICTIONARY_NOT_SET); JSG_STATIC_CONSTANT_NAMED( CONST_BROTLI_DECODER_ERROR_INVALID_ARGUMENTS, BROTLI_DECODER_ERROR_INVALID_ARGUMENTS); JSG_STATIC_CONSTANT_NAMED( CONST_BROTLI_DECODER_ERROR_ALLOC_CONTEXT_MODES, BROTLI_DECODER_ERROR_ALLOC_CONTEXT_MODES); JSG_STATIC_CONSTANT_NAMED( CONST_BROTLI_DECODER_ERROR_ALLOC_TREE_GROUPS, BROTLI_DECODER_ERROR_ALLOC_TREE_GROUPS); JSG_STATIC_CONSTANT_NAMED( CONST_BROTLI_DECODER_ERROR_ALLOC_CONTEXT_MAP, BROTLI_DECODER_ERROR_ALLOC_CONTEXT_MAP); JSG_STATIC_CONSTANT_NAMED( CONST_BROTLI_DECODER_ERROR_ALLOC_RING_BUFFER_1, BROTLI_DECODER_ERROR_ALLOC_RING_BUFFER_1); JSG_STATIC_CONSTANT_NAMED( CONST_BROTLI_DECODER_ERROR_ALLOC_RING_BUFFER_2, BROTLI_DECODER_ERROR_ALLOC_RING_BUFFER_2); JSG_STATIC_CONSTANT_NAMED(CONST_BROTLI_DECODER_ERROR_ALLOC_BLOCK_TYPE_TREES, BROTLI_DECODER_ERROR_ALLOC_BLOCK_TYPE_TREES); JSG_STATIC_CONSTANT_NAMED( CONST_BROTLI_DECODER_ERROR_UNREACHABLE, BROTLI_DECODER_ERROR_UNREACHABLE); // Zstd mode constants JSG_STATIC_CONSTANT_NAMED(CONST_ZSTD_ENCODE, static_cast(ZlibMode::ZSTD_ENCODE)); JSG_STATIC_CONSTANT_NAMED(CONST_ZSTD_DECODE, static_cast(ZlibMode::ZSTD_DECODE)); // Node.js aliases for mode constants (ZSTD_COMPRESS/ZSTD_DECOMPRESS) JSG_STATIC_CONSTANT_NAMED( CONST_ZSTD_COMPRESS, static_cast(ZlibMode::ZSTD_ENCODE)); JSG_STATIC_CONSTANT_NAMED( CONST_ZSTD_DECOMPRESS, static_cast(ZlibMode::ZSTD_DECODE)); // Zstd flush directives JSG_STATIC_CONSTANT_NAMED(CONST_ZSTD_e_continue, ZSTD_e_continue); JSG_STATIC_CONSTANT_NAMED(CONST_ZSTD_e_flush, ZSTD_e_flush); JSG_STATIC_CONSTANT_NAMED(CONST_ZSTD_e_end, ZSTD_e_end); // Zstd compression parameters JSG_STATIC_CONSTANT_NAMED(CONST_ZSTD_c_compressionLevel, ZSTD_c_compressionLevel); JSG_STATIC_CONSTANT_NAMED(CONST_ZSTD_c_windowLog, ZSTD_c_windowLog); JSG_STATIC_CONSTANT_NAMED(CONST_ZSTD_c_hashLog, ZSTD_c_hashLog); JSG_STATIC_CONSTANT_NAMED(CONST_ZSTD_c_chainLog, ZSTD_c_chainLog); JSG_STATIC_CONSTANT_NAMED(CONST_ZSTD_c_searchLog, ZSTD_c_searchLog); JSG_STATIC_CONSTANT_NAMED(CONST_ZSTD_c_minMatch, ZSTD_c_minMatch); JSG_STATIC_CONSTANT_NAMED(CONST_ZSTD_c_targetLength, ZSTD_c_targetLength); JSG_STATIC_CONSTANT_NAMED(CONST_ZSTD_c_strategy, ZSTD_c_strategy); JSG_STATIC_CONSTANT_NAMED( CONST_ZSTD_c_enableLongDistanceMatching, ZSTD_c_enableLongDistanceMatching); JSG_STATIC_CONSTANT_NAMED(CONST_ZSTD_c_ldmHashLog, ZSTD_c_ldmHashLog); JSG_STATIC_CONSTANT_NAMED(CONST_ZSTD_c_ldmMinMatch, ZSTD_c_ldmMinMatch); JSG_STATIC_CONSTANT_NAMED(CONST_ZSTD_c_ldmBucketSizeLog, ZSTD_c_ldmBucketSizeLog); JSG_STATIC_CONSTANT_NAMED(CONST_ZSTD_c_ldmHashRateLog, ZSTD_c_ldmHashRateLog); JSG_STATIC_CONSTANT_NAMED(CONST_ZSTD_c_contentSizeFlag, ZSTD_c_contentSizeFlag); JSG_STATIC_CONSTANT_NAMED(CONST_ZSTD_c_checksumFlag, ZSTD_c_checksumFlag); JSG_STATIC_CONSTANT_NAMED(CONST_ZSTD_c_dictIDFlag, ZSTD_c_dictIDFlag); JSG_STATIC_CONSTANT_NAMED(CONST_ZSTD_c_nbWorkers, ZSTD_c_nbWorkers); JSG_STATIC_CONSTANT_NAMED(CONST_ZSTD_c_jobSize, ZSTD_c_jobSize); JSG_STATIC_CONSTANT_NAMED(CONST_ZSTD_c_overlapLog, ZSTD_c_overlapLog); // Zstd decompression parameters JSG_STATIC_CONSTANT_NAMED(CONST_ZSTD_d_windowLogMax, ZSTD_d_windowLogMax); // Zstd strategy constants JSG_STATIC_CONSTANT_NAMED(CONST_ZSTD_fast, ZSTD_fast); JSG_STATIC_CONSTANT_NAMED(CONST_ZSTD_dfast, ZSTD_dfast); JSG_STATIC_CONSTANT_NAMED(CONST_ZSTD_greedy, ZSTD_greedy); JSG_STATIC_CONSTANT_NAMED(CONST_ZSTD_lazy, ZSTD_lazy); JSG_STATIC_CONSTANT_NAMED(CONST_ZSTD_lazy2, ZSTD_lazy2); JSG_STATIC_CONSTANT_NAMED(CONST_ZSTD_btlazy2, ZSTD_btlazy2); JSG_STATIC_CONSTANT_NAMED(CONST_ZSTD_btopt, ZSTD_btopt); JSG_STATIC_CONSTANT_NAMED(CONST_ZSTD_btultra, ZSTD_btultra); JSG_STATIC_CONSTANT_NAMED(CONST_ZSTD_btultra2, ZSTD_btultra2); // Zstd default compression level JSG_STATIC_CONSTANT_NAMED(CONST_ZSTD_CLEVEL_DEFAULT, ZSTD_CLEVEL_DEFAULT); // Zstd error codes JSG_STATIC_CONSTANT_NAMED(CONST_ZSTD_error_no_error, ZSTD_error_no_error); JSG_STATIC_CONSTANT_NAMED(CONST_ZSTD_error_GENERIC, ZSTD_error_GENERIC); JSG_STATIC_CONSTANT_NAMED(CONST_ZSTD_error_prefix_unknown, ZSTD_error_prefix_unknown); JSG_STATIC_CONSTANT_NAMED(CONST_ZSTD_error_version_unsupported, ZSTD_error_version_unsupported); JSG_STATIC_CONSTANT_NAMED( CONST_ZSTD_error_frameParameter_unsupported, ZSTD_error_frameParameter_unsupported); JSG_STATIC_CONSTANT_NAMED( CONST_ZSTD_error_frameParameter_windowTooLarge, ZSTD_error_frameParameter_windowTooLarge); JSG_STATIC_CONSTANT_NAMED(CONST_ZSTD_error_corruption_detected, ZSTD_error_corruption_detected); JSG_STATIC_CONSTANT_NAMED(CONST_ZSTD_error_checksum_wrong, ZSTD_error_checksum_wrong); JSG_STATIC_CONSTANT_NAMED( CONST_ZSTD_error_literals_headerWrong, ZSTD_error_literals_headerWrong); JSG_STATIC_CONSTANT_NAMED( CONST_ZSTD_error_dictionary_corrupted, ZSTD_error_dictionary_corrupted); JSG_STATIC_CONSTANT_NAMED(CONST_ZSTD_error_dictionary_wrong, ZSTD_error_dictionary_wrong); JSG_STATIC_CONSTANT_NAMED( CONST_ZSTD_error_dictionaryCreation_failed, ZSTD_error_dictionaryCreation_failed); JSG_STATIC_CONSTANT_NAMED( CONST_ZSTD_error_parameter_unsupported, ZSTD_error_parameter_unsupported); JSG_STATIC_CONSTANT_NAMED(CONST_ZSTD_error_parameter_combination_unsupported, ZSTD_error_parameter_combination_unsupported); JSG_STATIC_CONSTANT_NAMED( CONST_ZSTD_error_parameter_outOfBound, ZSTD_error_parameter_outOfBound); JSG_STATIC_CONSTANT_NAMED(CONST_ZSTD_error_tableLog_tooLarge, ZSTD_error_tableLog_tooLarge); JSG_STATIC_CONSTANT_NAMED( CONST_ZSTD_error_maxSymbolValue_tooLarge, ZSTD_error_maxSymbolValue_tooLarge); JSG_STATIC_CONSTANT_NAMED( CONST_ZSTD_error_maxSymbolValue_tooSmall, ZSTD_error_maxSymbolValue_tooSmall); JSG_STATIC_CONSTANT_NAMED(CONST_ZSTD_error_stabilityCondition_notRespected, ZSTD_error_stabilityCondition_notRespected); JSG_STATIC_CONSTANT_NAMED(CONST_ZSTD_error_stage_wrong, ZSTD_error_stage_wrong); JSG_STATIC_CONSTANT_NAMED(CONST_ZSTD_error_init_missing, ZSTD_error_init_missing); JSG_STATIC_CONSTANT_NAMED(CONST_ZSTD_error_memory_allocation, ZSTD_error_memory_allocation); JSG_STATIC_CONSTANT_NAMED(CONST_ZSTD_error_workSpace_tooSmall, ZSTD_error_workSpace_tooSmall); JSG_STATIC_CONSTANT_NAMED(CONST_ZSTD_error_dstSize_tooSmall, ZSTD_error_dstSize_tooSmall); JSG_STATIC_CONSTANT_NAMED(CONST_ZSTD_error_srcSize_wrong, ZSTD_error_srcSize_wrong); JSG_STATIC_CONSTANT_NAMED(CONST_ZSTD_error_dstBuffer_null, ZSTD_error_dstBuffer_null); JSG_STATIC_CONSTANT_NAMED( CONST_ZSTD_error_noForwardProgress_destFull, ZSTD_error_noForwardProgress_destFull); JSG_STATIC_CONSTANT_NAMED( CONST_ZSTD_error_noForwardProgress_inputEmpty, ZSTD_error_noForwardProgress_inputEmpty); } }; #define EW_NODE_ZLIB_ISOLATE_TYPES \ api::node::ZlibUtil, api::node::ZlibUtil::ZlibStream, \ api::node::ZlibUtil::BrotliCompressionStream, \ api::node::ZlibUtil::BrotliCompressionStream, \ api::node::ZlibUtil::ZstdCompressionStream, \ api::node::ZlibUtil::ZstdCompressionStream, \ api::node::ZlibUtil::CompressionStream, \ api::node::ZlibUtil::CompressionStream, \ api::node::ZlibUtil::CompressionStream, \ api::node::ZlibUtil::CompressionStream, \ api::node::ZlibUtil::CompressionStream, \ api::node::ZlibContext::Options, api::node::BrotliContext::Options, \ api::node::ZstdContext::Options } // namespace workerd::api::node KJ_DECLARE_NON_POLYMORPHIC(BrotliEncoderStateStruct) KJ_DECLARE_NON_POLYMORPHIC(BrotliDecoderStateStruct) KJ_DECLARE_NON_POLYMORPHIC(ZSTD_CCtx) KJ_DECLARE_NON_POLYMORPHIC(ZSTD_DCtx)