1 // Copyright Joyent, Inc. and other Node contributors.
2 //
3 // Permission is hereby granted, free of charge, to any person obtaining a
4 // copy of this software and associated documentation files (the
5 // "Software"), to deal in the Software without restriction, including
6 // without limitation the rights to use, copy, modify, merge, publish,
7 // distribute, sublicense, and/or sell copies of the Software, and to permit
8 // persons to whom the Software is furnished to do so, subject to the
9 // following conditions:
10 //
11 // The above copyright notice and this permission notice shall be included
12 // in all copies or substantial portions of the Software.
13 //
14 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
15 // OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
17 // NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
18 // DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
19 // OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
20 // USE OR OTHER DEALINGS IN THE SOFTWARE.
21
22 #include "memory_tracker-inl.h"
23 #include "node.h"
24 #include "node_buffer.h"
25
26 #include "async_wrap-inl.h"
27 #include "env-inl.h"
28 #include "node_external_reference.h"
29 #include "threadpoolwork-inl.h"
30 #include "util-inl.h"
31
32 #include "v8.h"
33
34 #include "brotli/encode.h"
35 #include "brotli/decode.h"
36 #include "zlib.h"
37
38 #include <sys/types.h>
39
40 #include <cerrno>
41 #include <cstdlib>
42 #include <cstring>
43 #include <atomic>
44
45 namespace node {
46
47 using v8::ArrayBuffer;
48 using v8::Context;
49 using v8::Function;
50 using v8::FunctionCallbackInfo;
51 using v8::FunctionTemplate;
52 using v8::HandleScope;
53 using v8::Int32;
54 using v8::Integer;
55 using v8::Isolate;
56 using v8::Local;
57 using v8::Object;
58 using v8::Uint32Array;
59 using v8::Value;
60
61 namespace {
62
63 // Fewer than 64 bytes per chunk is not recommended.
64 // Technically it could work with as few as 8, but even 64 bytes
65 // is low. Usually a MB or more is best.
66 #define Z_MIN_CHUNK 64
67 #define Z_MAX_CHUNK std::numeric_limits<double>::infinity()
68 #define Z_DEFAULT_CHUNK (16 * 1024)
69 #define Z_MIN_MEMLEVEL 1
70 #define Z_MAX_MEMLEVEL 9
71 #define Z_DEFAULT_MEMLEVEL 8
72 #define Z_MIN_LEVEL -1
73 #define Z_MAX_LEVEL 9
74 #define Z_DEFAULT_LEVEL Z_DEFAULT_COMPRESSION
75 #define Z_MIN_WINDOWBITS 8
76 #define Z_MAX_WINDOWBITS 15
77 #define Z_DEFAULT_WINDOWBITS 15
78
79 #define ZLIB_ERROR_CODES(V) \
80 V(Z_OK) \
81 V(Z_STREAM_END) \
82 V(Z_NEED_DICT) \
83 V(Z_ERRNO) \
84 V(Z_STREAM_ERROR) \
85 V(Z_DATA_ERROR) \
86 V(Z_MEM_ERROR) \
87 V(Z_BUF_ERROR) \
88 V(Z_VERSION_ERROR) \
89
ZlibStrerror(int err)90 inline const char* ZlibStrerror(int err) {
91 #define V(code) if (err == code) return #code;
92 ZLIB_ERROR_CODES(V)
93 #undef V
94 return "Z_UNKNOWN_ERROR";
95 }
96
97 enum node_zlib_mode {
98 NONE,
99 DEFLATE,
100 INFLATE,
101 GZIP,
102 GUNZIP,
103 DEFLATERAW,
104 INFLATERAW,
105 UNZIP,
106 BROTLI_DECODE,
107 BROTLI_ENCODE
108 };
109
110 constexpr uint8_t GZIP_HEADER_ID1 = 0x1f;
111 constexpr uint8_t GZIP_HEADER_ID2 = 0x8b;
112
113 struct CompressionError {
CompressionErrornode::__anon15438::CompressionError114 CompressionError(const char* message, const char* code, int err)
115 : message(message),
116 code(code),
117 err(err) {
118 CHECK_NOT_NULL(message);
119 }
120
121 CompressionError() = default;
122
123 const char* message = nullptr;
124 const char* code = nullptr;
125 int err = 0;
126
IsErrornode::__anon15438::CompressionError127 inline bool IsError() const { return code != nullptr; }
128 };
129
130 class ZlibContext final : public MemoryRetainer {
131 public:
132 ZlibContext() = default;
133
134 // Streaming-related, should be available for all compression libraries:
135 void Close();
136 void DoThreadPoolWork();
137 void SetBuffers(const char* in, uint32_t in_len, char* out, uint32_t out_len);
138 void SetFlush(int flush);
139 void GetAfterWriteOffsets(uint32_t* avail_in, uint32_t* avail_out) const;
140 CompressionError GetErrorInfo() const;
SetMode(node_zlib_mode mode)141 inline void SetMode(node_zlib_mode mode) { mode_ = mode; }
142 CompressionError ResetStream();
143
144 // Zlib-specific:
145 void Init(int level, int window_bits, int mem_level, int strategy,
146 std::vector<unsigned char>&& dictionary);
147 void SetAllocationFunctions(alloc_func alloc, free_func free, void* opaque);
148 CompressionError SetParams(int level, int strategy);
149
150 SET_MEMORY_INFO_NAME(ZlibContext)
151 SET_SELF_SIZE(ZlibContext)
152
153 void MemoryInfo(MemoryTracker* tracker) const override {
154 tracker->TrackField("dictionary", dictionary_);
155 }
156
157 ZlibContext(const ZlibContext&) = delete;
158 ZlibContext& operator=(const ZlibContext&) = delete;
159
160 private:
161 CompressionError ErrorForMessage(const char* message) const;
162 CompressionError SetDictionary();
163 bool InitZlib();
164
165 Mutex mutex_; // Protects zlib_init_done_.
166 bool zlib_init_done_ = false;
167 int err_ = 0;
168 int flush_ = 0;
169 int level_ = 0;
170 int mem_level_ = 0;
171 node_zlib_mode mode_ = NONE;
172 int strategy_ = 0;
173 int window_bits_ = 0;
174 unsigned int gzip_id_bytes_read_ = 0;
175 std::vector<unsigned char> dictionary_;
176
177 z_stream strm_;
178 };
179
180 // Brotli has different data types for compression and decompression streams,
181 // so some of the specifics are implemented in more specific subclasses
182 class BrotliContext : public MemoryRetainer {
183 public:
184 BrotliContext() = default;
185
186 void SetBuffers(const char* in, uint32_t in_len, char* out, uint32_t out_len);
187 void SetFlush(int flush);
188 void GetAfterWriteOffsets(uint32_t* avail_in, uint32_t* avail_out) const;
SetMode(node_zlib_mode mode)189 inline void SetMode(node_zlib_mode mode) { mode_ = mode; }
190
191 BrotliContext(const BrotliContext&) = delete;
192 BrotliContext& operator=(const BrotliContext&) = delete;
193
194 protected:
195 node_zlib_mode mode_ = NONE;
196 const uint8_t* next_in_ = nullptr;
197 uint8_t* next_out_ = nullptr;
198 size_t avail_in_ = 0;
199 size_t avail_out_ = 0;
200 BrotliEncoderOperation flush_ = BROTLI_OPERATION_PROCESS;
201 // TODO(addaleax): These should not need to be stored here.
202 // This is currently only done this way to make implementing ResetStream()
203 // easier.
204 brotli_alloc_func alloc_ = nullptr;
205 brotli_free_func free_ = nullptr;
206 void* alloc_opaque_ = nullptr;
207 };
208
209 class BrotliEncoderContext final : public BrotliContext {
210 public:
211 void Close();
212 void DoThreadPoolWork();
213 CompressionError Init(brotli_alloc_func alloc,
214 brotli_free_func free,
215 void* opaque);
216 CompressionError ResetStream();
217 CompressionError SetParams(int key, uint32_t value);
218 CompressionError GetErrorInfo() const;
219
220 SET_MEMORY_INFO_NAME(BrotliEncoderContext)
221 SET_SELF_SIZE(BrotliEncoderContext)
222 SET_NO_MEMORY_INFO() // state_ is covered through allocation tracking.
223
224 private:
225 bool last_result_ = false;
226 DeleteFnPtr<BrotliEncoderState, BrotliEncoderDestroyInstance> state_;
227 };
228
229 class BrotliDecoderContext final : public BrotliContext {
230 public:
231 void Close();
232 void DoThreadPoolWork();
233 CompressionError Init(brotli_alloc_func alloc,
234 brotli_free_func free,
235 void* opaque);
236 CompressionError ResetStream();
237 CompressionError SetParams(int key, uint32_t value);
238 CompressionError GetErrorInfo() const;
239
240 SET_MEMORY_INFO_NAME(BrotliDecoderContext)
241 SET_SELF_SIZE(BrotliDecoderContext)
242 SET_NO_MEMORY_INFO() // state_ is covered through allocation tracking.
243
244 private:
245 BrotliDecoderResult last_result_ = BROTLI_DECODER_RESULT_SUCCESS;
246 BrotliDecoderErrorCode error_ = BROTLI_DECODER_NO_ERROR;
247 std::string error_string_;
248 DeleteFnPtr<BrotliDecoderState, BrotliDecoderDestroyInstance> state_;
249 };
250
251 template <typename CompressionContext>
252 class CompressionStream : public AsyncWrap, public ThreadPoolWork {
253 public:
254 enum InternalFields {
255 kCompressionStreamBaseField = AsyncWrap::kInternalFieldCount,
256 kWriteJSCallback,
257 kInternalFieldCount
258 };
259
CompressionStream(Environment* env, Local<Object> wrap)260 CompressionStream(Environment* env, Local<Object> wrap)
261 : AsyncWrap(env, wrap, AsyncWrap::PROVIDER_ZLIB),
262 ThreadPoolWork(env, "zlib"),
263 write_result_(nullptr) {
264 MakeWeak();
265 }
266
267 ~CompressionStream() override {
268 CHECK(!write_in_progress_);
269 Close();
270 CHECK_EQ(zlib_memory_, 0);
271 CHECK_EQ(unreported_allocations_, 0);
272 }
273
Close()274 void Close() {
275 if (write_in_progress_) {
276 pending_close_ = true;
277 return;
278 }
279
280 pending_close_ = false;
281 closed_ = true;
282 CHECK(init_done_ && "close before init");
283
284 AllocScope alloc_scope(this);
285 ctx_.Close();
286 }
287
288
Close(const FunctionCallbackInfo<Value>& args)289 static void Close(const FunctionCallbackInfo<Value>& args) {
290 CompressionStream* ctx;
291 ASSIGN_OR_RETURN_UNWRAP(&ctx, args.Holder());
292 ctx->Close();
293 }
294
295
296 // write(flush, in, in_off, in_len, out, out_off, out_len)
297 template <bool async>
Write(const FunctionCallbackInfo<Value>& args)298 static void Write(const FunctionCallbackInfo<Value>& args) {
299 Environment* env = Environment::GetCurrent(args);
300 Local<Context> context = env->context();
301 CHECK_EQ(args.Length(), 7);
302
303 uint32_t in_off, in_len, out_off, out_len, flush;
304 const char* in;
305 char* out;
306
307 CHECK_EQ(false, args[0]->IsUndefined() && "must provide flush value");
308 if (!args[0]->Uint32Value(context).To(&flush)) return;
309
310 if (flush != Z_NO_FLUSH &&
311 flush != Z_PARTIAL_FLUSH &&
312 flush != Z_SYNC_FLUSH &&
313 flush != Z_FULL_FLUSH &&
314 flush != Z_FINISH &&
315 flush != Z_BLOCK) {
316 UNREACHABLE("Invalid flush value");
317 }
318
319 if (args[1]->IsNull()) {
320 // just a flush
321 in = nullptr;
322 in_len = 0;
323 in_off = 0;
324 } else {
325 CHECK(Buffer::HasInstance(args[1]));
326 Local<Object> in_buf = args[1].As<Object>();
327 if (!args[2]->Uint32Value(context).To(&in_off)) return;
328 if (!args[3]->Uint32Value(context).To(&in_len)) return;
329
330 CHECK(Buffer::IsWithinBounds(in_off, in_len, Buffer::Length(in_buf)));
331 in = Buffer::Data(in_buf) + in_off;
332 }
333
334 CHECK(Buffer::HasInstance(args[4]));
335 Local<Object> out_buf = args[4].As<Object>();
336 if (!args[5]->Uint32Value(context).To(&out_off)) return;
337 if (!args[6]->Uint32Value(context).To(&out_len)) return;
338 CHECK(Buffer::IsWithinBounds(out_off, out_len, Buffer::Length(out_buf)));
339 out = Buffer::Data(out_buf) + out_off;
340
341 CompressionStream* ctx;
342 ASSIGN_OR_RETURN_UNWRAP(&ctx, args.Holder());
343
344 ctx->Write<async>(flush, in, in_len, out, out_len);
345 }
346
347 template <bool async>
Write(uint32_t flush, const char* in, uint32_t in_len, char* out, uint32_t out_len)348 void Write(uint32_t flush,
349 const char* in, uint32_t in_len,
350 char* out, uint32_t out_len) {
351 AllocScope alloc_scope(this);
352
353 CHECK(init_done_ && "write before init");
354 CHECK(!closed_ && "already finalized");
355
356 CHECK_EQ(false, write_in_progress_);
357 CHECK_EQ(false, pending_close_);
358 write_in_progress_ = true;
359 Ref();
360
361 ctx_.SetBuffers(in, in_len, out, out_len);
362 ctx_.SetFlush(flush);
363
364 if constexpr (!async) {
365 // sync version
366 AsyncWrap::env()->PrintSyncTrace();
367 DoThreadPoolWork();
368 if (CheckError()) {
369 UpdateWriteResult();
370 write_in_progress_ = false;
371 }
372 Unref();
373 return;
374 }
375
376 // async version
377 ScheduleWork();
378 }
379
UpdateWriteResult()380 void UpdateWriteResult() {
381 ctx_.GetAfterWriteOffsets(&write_result_[1], &write_result_[0]);
382 }
383
384 // thread pool!
385 // This function may be called multiple times on the uv_work pool
386 // for a single write() call, until all of the input bytes have
387 // been consumed.
388 void DoThreadPoolWork() override {
389 ctx_.DoThreadPoolWork();
390 }
391
392
CheckError()393 bool CheckError() {
394 const CompressionError err = ctx_.GetErrorInfo();
395 if (!err.IsError()) return true;
396 EmitError(err);
397 return false;
398 }
399
400
401 // v8 land!
402 void AfterThreadPoolWork(int status) override {
403 DCHECK(init_done_);
404 AllocScope alloc_scope(this);
405 auto on_scope_leave = OnScopeLeave([&]() { Unref(); });
406
407 write_in_progress_ = false;
408
409 if (status == UV_ECANCELED) {
410 Close();
411 return;
412 }
413
414 CHECK_EQ(status, 0);
415
416 Environment* env = AsyncWrap::env();
417 HandleScope handle_scope(env->isolate());
418 Context::Scope context_scope(env->context());
419
420 if (!CheckError())
421 return;
422
423 UpdateWriteResult();
424
425 // call the write() cb
426 Local<Value> cb =
427 object()->GetInternalField(kWriteJSCallback).template As<Value>();
428 MakeCallback(cb.As<Function>(), 0, nullptr);
429
430 if (pending_close_)
431 Close();
432 }
433
434 // TODO(addaleax): Switch to modern error system (node_errors.h).
EmitError(const CompressionError& err)435 void EmitError(const CompressionError& err) {
436 Environment* env = AsyncWrap::env();
437 // If you hit this assertion, you forgot to enter the v8::Context first.
438 CHECK_EQ(env->context(), env->isolate()->GetCurrentContext());
439
440 HandleScope scope(env->isolate());
441 Local<Value> args[] = {
442 OneByteString(env->isolate(), err.message),
443 Integer::New(env->isolate(), err.err),
444 OneByteString(env->isolate(), err.code)
445 };
446 MakeCallback(env->onerror_string(), arraysize(args), args);
447
448 // no hope of rescue.
449 write_in_progress_ = false;
450 if (pending_close_)
451 Close();
452 }
453
Reset(const FunctionCallbackInfo<Value> &args)454 static void Reset(const FunctionCallbackInfo<Value> &args) {
455 CompressionStream* wrap;
456 ASSIGN_OR_RETURN_UNWRAP(&wrap, args.Holder());
457
458 AllocScope alloc_scope(wrap);
459 const CompressionError err = wrap->context()->ResetStream();
460 if (err.IsError())
461 wrap->EmitError(err);
462 }
463
464 void MemoryInfo(MemoryTracker* tracker) const override {
465 tracker->TrackField("compression context", ctx_);
466 tracker->TrackFieldWithSize("zlib_memory",
467 zlib_memory_ + unreported_allocations_);
468 }
469
470 protected:
context()471 CompressionContext* context() { return &ctx_; }
472
InitStream(uint32_t* write_result, Local<Function> write_js_callback)473 void InitStream(uint32_t* write_result, Local<Function> write_js_callback) {
474 write_result_ = write_result;
475 object()->SetInternalField(kWriteJSCallback, write_js_callback);
476 init_done_ = true;
477 }
478
479 // Allocation functions provided to zlib itself. We store the real size of
480 // the allocated memory chunk just before the "payload" memory we return
481 // to zlib.
482 // Because we use zlib off the thread pool, we can not report memory directly
483 // to V8; rather, we first store it as "unreported" memory in a separate
484 // field and later report it back from the main thread.
AllocForZlib(void* data, uInt items, uInt size)485 static void* AllocForZlib(void* data, uInt items, uInt size) {
486 size_t real_size =
487 MultiplyWithOverflowCheck(static_cast<size_t>(items),
488 static_cast<size_t>(size));
489 return AllocForBrotli(data, real_size);
490 }
491
AllocForBrotli(void* data, size_t size)492 static void* AllocForBrotli(void* data, size_t size) {
493 size += sizeof(size_t);
494 CompressionStream* ctx = static_cast<CompressionStream*>(data);
495 char* memory = UncheckedMalloc(size);
496 if (UNLIKELY(memory == nullptr)) return nullptr;
497 *reinterpret_cast<size_t*>(memory) = size;
498 ctx->unreported_allocations_.fetch_add(size,
499 std::memory_order_relaxed);
500 return memory + sizeof(size_t);
501 }
502
FreeForZlib(void* data, void* pointer)503 static void FreeForZlib(void* data, void* pointer) {
504 if (UNLIKELY(pointer == nullptr)) return;
505 CompressionStream* ctx = static_cast<CompressionStream*>(data);
506 char* real_pointer = static_cast<char*>(pointer) - sizeof(size_t);
507 size_t real_size = *reinterpret_cast<size_t*>(real_pointer);
508 ctx->unreported_allocations_.fetch_sub(real_size,
509 std::memory_order_relaxed);
510 free(real_pointer);
511 }
512
513 // This is called on the main thread after zlib may have allocated something
514 // in order to report it back to V8.
AdjustAmountOfExternalAllocatedMemory()515 void AdjustAmountOfExternalAllocatedMemory() {
516 ssize_t report =
517 unreported_allocations_.exchange(0, std::memory_order_relaxed);
518 if (report == 0) return;
519 CHECK_IMPLIES(report < 0, zlib_memory_ >= static_cast<size_t>(-report));
520 zlib_memory_ += report;
521 AsyncWrap::env()->isolate()->AdjustAmountOfExternalAllocatedMemory(report);
522 }
523
524 struct AllocScope {
AllocScopenode::__anon15438::CompressionStream::AllocScope525 explicit AllocScope(CompressionStream* stream) : stream(stream) {}
~AllocScopenode::__anon15438::CompressionStream::AllocScope526 ~AllocScope() { stream->AdjustAmountOfExternalAllocatedMemory(); }
527 CompressionStream* stream;
528 };
529
530 private:
Ref()531 void Ref() {
532 if (++refs_ == 1) {
533 ClearWeak();
534 }
535 }
536
Unref()537 void Unref() {
538 CHECK_GT(refs_, 0);
539 if (--refs_ == 0) {
540 MakeWeak();
541 }
542 }
543
544 bool init_done_ = false;
545 bool write_in_progress_ = false;
546 bool pending_close_ = false;
547 bool closed_ = false;
548 unsigned int refs_ = 0;
549 uint32_t* write_result_ = nullptr;
550 std::atomic<ssize_t> unreported_allocations_{0};
551 size_t zlib_memory_ = 0;
552
553 CompressionContext ctx_;
554 };
555
556 class ZlibStream final : public CompressionStream<ZlibContext> {
557 public:
ZlibStream(Environment* env, Local<Object> wrap, node_zlib_mode mode)558 ZlibStream(Environment* env, Local<Object> wrap, node_zlib_mode mode)
559 : CompressionStream(env, wrap) {
560 context()->SetMode(mode);
561 }
562
New(const FunctionCallbackInfo<Value>& args)563 static void New(const FunctionCallbackInfo<Value>& args) {
564 Environment* env = Environment::GetCurrent(args);
565 CHECK(args[0]->IsInt32());
566 node_zlib_mode mode =
567 static_cast<node_zlib_mode>(args[0].As<Int32>()->Value());
568 new ZlibStream(env, args.This(), mode);
569 }
570
571 // just pull the ints out of the args and call the other Init
Init(const FunctionCallbackInfo<Value>& args)572 static void Init(const FunctionCallbackInfo<Value>& args) {
573 // Refs: https://github.com/nodejs/node/issues/16649
574 // Refs: https://github.com/nodejs/node/issues/14161
575 if (args.Length() == 5) {
576 fprintf(stderr,
577 "WARNING: You are likely using a version of node-tar or npm that "
578 "is incompatible with this version of Node.js.\nPlease use "
579 "either the version of npm that is bundled with Node.js, or "
580 "a version of npm (> 5.5.1 or < 5.4.0) or node-tar (> 4.0.1) "
581 "that is compatible with Node.js 9 and above.\n");
582 }
583 CHECK(args.Length() == 7 &&
584 "init(windowBits, level, memLevel, strategy, writeResult, writeCallback,"
585 " dictionary)");
586
587 ZlibStream* wrap;
588 ASSIGN_OR_RETURN_UNWRAP(&wrap, args.Holder());
589
590 Local<Context> context = args.GetIsolate()->GetCurrentContext();
591
592 // windowBits is special. On the compression side, 0 is an invalid value.
593 // But on the decompression side, a value of 0 for windowBits tells zlib
594 // to use the window size in the zlib header of the compressed stream.
595 uint32_t window_bits;
596 if (!args[0]->Uint32Value(context).To(&window_bits)) return;
597
598 int32_t level;
599 if (!args[1]->Int32Value(context).To(&level)) return;
600
601 uint32_t mem_level;
602 if (!args[2]->Uint32Value(context).To(&mem_level)) return;
603
604 uint32_t strategy;
605 if (!args[3]->Uint32Value(context).To(&strategy)) return;
606
607 CHECK(args[4]->IsUint32Array());
608 Local<Uint32Array> array = args[4].As<Uint32Array>();
609 Local<ArrayBuffer> ab = array->Buffer();
610 uint32_t* write_result = static_cast<uint32_t*>(ab->Data());
611
612 CHECK(args[5]->IsFunction());
613 Local<Function> write_js_callback = args[5].As<Function>();
614
615 std::vector<unsigned char> dictionary;
616 if (Buffer::HasInstance(args[6])) {
617 unsigned char* data =
618 reinterpret_cast<unsigned char*>(Buffer::Data(args[6]));
619 dictionary = std::vector<unsigned char>(
620 data,
621 data + Buffer::Length(args[6]));
622 }
623
624 wrap->InitStream(write_result, write_js_callback);
625
626 AllocScope alloc_scope(wrap);
627 wrap->context()->SetAllocationFunctions(
628 AllocForZlib, FreeForZlib, static_cast<CompressionStream*>(wrap));
629 wrap->context()->Init(level, window_bits, mem_level, strategy,
630 std::move(dictionary));
631 }
632
Params(const FunctionCallbackInfo<Value>& args)633 static void Params(const FunctionCallbackInfo<Value>& args) {
634 CHECK(args.Length() == 2 && "params(level, strategy)");
635 ZlibStream* wrap;
636 ASSIGN_OR_RETURN_UNWRAP(&wrap, args.Holder());
637 Local<Context> context = args.GetIsolate()->GetCurrentContext();
638 int level;
639 if (!args[0]->Int32Value(context).To(&level)) return;
640 int strategy;
641 if (!args[1]->Int32Value(context).To(&strategy)) return;
642
643 AllocScope alloc_scope(wrap);
644 const CompressionError err = wrap->context()->SetParams(level, strategy);
645 if (err.IsError())
646 wrap->EmitError(err);
647 }
648
649 SET_MEMORY_INFO_NAME(ZlibStream)
650 SET_SELF_SIZE(ZlibStream)
651 };
652
653 template <typename CompressionContext>
654 class BrotliCompressionStream final :
655 public CompressionStream<CompressionContext> {
656 public:
BrotliCompressionStream(Environment* env, Local<Object> wrap, node_zlib_mode mode)657 BrotliCompressionStream(Environment* env,
658 Local<Object> wrap,
659 node_zlib_mode mode)
660 : CompressionStream<CompressionContext>(env, wrap) {
661 context()->SetMode(mode);
662 }
663
context()664 inline CompressionContext* context() {
665 return this->CompressionStream<CompressionContext>::context();
666 }
667 typedef typename CompressionStream<CompressionContext>::AllocScope AllocScope;
668
New(const FunctionCallbackInfo<Value>& args)669 static void New(const FunctionCallbackInfo<Value>& args) {
670 Environment* env = Environment::GetCurrent(args);
671 CHECK(args[0]->IsInt32());
672 node_zlib_mode mode =
673 static_cast<node_zlib_mode>(args[0].As<Int32>()->Value());
674 new BrotliCompressionStream(env, args.This(), mode);
675 }
676
Init(const FunctionCallbackInfo<Value>& args)677 static void Init(const FunctionCallbackInfo<Value>& args) {
678 BrotliCompressionStream* wrap;
679 ASSIGN_OR_RETURN_UNWRAP(&wrap, args.Holder());
680 CHECK(args.Length() == 3 && "init(params, writeResult, writeCallback)");
681
682 CHECK(args[1]->IsUint32Array());
683 uint32_t* write_result = reinterpret_cast<uint32_t*>(Buffer::Data(args[1]));
684
685 CHECK(args[2]->IsFunction());
686 Local<Function> write_js_callback = args[2].As<Function>();
687 wrap->InitStream(write_result, write_js_callback);
688
689 AllocScope alloc_scope(wrap);
690 CompressionError err =
691 wrap->context()->Init(
692 CompressionStream<CompressionContext>::AllocForBrotli,
693 CompressionStream<CompressionContext>::FreeForZlib,
694 static_cast<CompressionStream<CompressionContext>*>(wrap));
695 if (err.IsError()) {
696 wrap->EmitError(err);
697 args.GetReturnValue().Set(false);
698 return;
699 }
700
701 CHECK(args[0]->IsUint32Array());
702 const uint32_t* data = reinterpret_cast<uint32_t*>(Buffer::Data(args[0]));
703 size_t len = args[0].As<Uint32Array>()->Length();
704
705 for (int i = 0; static_cast<size_t>(i) < len; i++) {
706 if (data[i] == static_cast<uint32_t>(-1))
707 continue;
708 err = wrap->context()->SetParams(i, data[i]);
709 if (err.IsError()) {
710 wrap->EmitError(err);
711 args.GetReturnValue().Set(false);
712 return;
713 }
714 }
715
716 args.GetReturnValue().Set(true);
717 }
718
Params(const FunctionCallbackInfo<Value>& args)719 static void Params(const FunctionCallbackInfo<Value>& args) {
720 // Currently a no-op, and not accessed from JS land.
721 // At some point Brotli may support changing parameters on the fly,
722 // in which case we can implement this and a JS equivalent similar to
723 // the zlib Params() function.
724 }
725
726 SET_MEMORY_INFO_NAME(BrotliCompressionStream)
727 SET_SELF_SIZE(BrotliCompressionStream)
728 };
729
730 using BrotliEncoderStream = BrotliCompressionStream<BrotliEncoderContext>;
731 using BrotliDecoderStream = BrotliCompressionStream<BrotliDecoderContext>;
732
Close()733 void ZlibContext::Close() {
734 {
735 Mutex::ScopedLock lock(mutex_);
736 if (!zlib_init_done_) {
737 dictionary_.clear();
738 mode_ = NONE;
739 return;
740 }
741 }
742
743 CHECK_LE(mode_, UNZIP);
744
745 int status = Z_OK;
746 if (mode_ == DEFLATE || mode_ == GZIP || mode_ == DEFLATERAW) {
747 status = deflateEnd(&strm_);
748 } else if (mode_ == INFLATE || mode_ == GUNZIP || mode_ == INFLATERAW ||
749 mode_ == UNZIP) {
750 status = inflateEnd(&strm_);
751 }
752
753 CHECK(status == Z_OK || status == Z_DATA_ERROR);
754 mode_ = NONE;
755
756 dictionary_.clear();
757 }
758
759
DoThreadPoolWork()760 void ZlibContext::DoThreadPoolWork() {
761 bool first_init_call = InitZlib();
762 if (first_init_call && err_ != Z_OK) {
763 return;
764 }
765
766 const Bytef* next_expected_header_byte = nullptr;
767
768 // If the avail_out is left at 0, then it means that it ran out
769 // of room. If there was avail_out left over, then it means
770 // that all of the input was consumed.
771 switch (mode_) {
772 case DEFLATE:
773 case GZIP:
774 case DEFLATERAW:
775 err_ = deflate(&strm_, flush_);
776 break;
777 case UNZIP:
778 if (strm_.avail_in > 0) {
779 next_expected_header_byte = strm_.next_in;
780 }
781
782 switch (gzip_id_bytes_read_) {
783 case 0:
784 if (next_expected_header_byte == nullptr) {
785 break;
786 }
787
788 if (*next_expected_header_byte == GZIP_HEADER_ID1) {
789 gzip_id_bytes_read_ = 1;
790 next_expected_header_byte++;
791
792 if (strm_.avail_in == 1) {
793 // The only available byte was already read.
794 break;
795 }
796 } else {
797 mode_ = INFLATE;
798 break;
799 }
800
801 [[fallthrough]];
802 case 1:
803 if (next_expected_header_byte == nullptr) {
804 break;
805 }
806
807 if (*next_expected_header_byte == GZIP_HEADER_ID2) {
808 gzip_id_bytes_read_ = 2;
809 mode_ = GUNZIP;
810 } else {
811 // There is no actual difference between INFLATE and INFLATERAW
812 // (after initialization).
813 mode_ = INFLATE;
814 }
815
816 break;
817 default:
818 UNREACHABLE("invalid number of gzip magic number bytes read");
819 }
820
821 [[fallthrough]];
822 case INFLATE:
823 case GUNZIP:
824 case INFLATERAW:
825 err_ = inflate(&strm_, flush_);
826
827 // If data was encoded with dictionary (INFLATERAW will have it set in
828 // SetDictionary, don't repeat that here)
829 if (mode_ != INFLATERAW &&
830 err_ == Z_NEED_DICT &&
831 !dictionary_.empty()) {
832 // Load it
833 err_ = inflateSetDictionary(&strm_,
834 dictionary_.data(),
835 dictionary_.size());
836 if (err_ == Z_OK) {
837 // And try to decode again
838 err_ = inflate(&strm_, flush_);
839 } else if (err_ == Z_DATA_ERROR) {
840 // Both inflateSetDictionary() and inflate() return Z_DATA_ERROR.
841 // Make it possible for After() to tell a bad dictionary from bad
842 // input.
843 err_ = Z_NEED_DICT;
844 }
845 }
846
847 while (strm_.avail_in > 0 &&
848 mode_ == GUNZIP &&
849 err_ == Z_STREAM_END &&
850 strm_.next_in[0] != 0x00) {
851 // Bytes remain in input buffer. Perhaps this is another compressed
852 // member in the same archive, or just trailing garbage.
853 // Trailing zero bytes are okay, though, since they are frequently
854 // used for padding.
855
856 ResetStream();
857 err_ = inflate(&strm_, flush_);
858 }
859 break;
860 default:
861 UNREACHABLE();
862 }
863 }
864
865
SetBuffers(const char* in, uint32_t in_len, char* out, uint32_t out_len)866 void ZlibContext::SetBuffers(const char* in, uint32_t in_len,
867 char* out, uint32_t out_len) {
868 strm_.avail_in = in_len;
869 strm_.next_in = const_cast<Bytef*>(reinterpret_cast<const Bytef*>(in));
870 strm_.avail_out = out_len;
871 strm_.next_out = reinterpret_cast<Bytef*>(out);
872 }
873
874
SetFlush(int flush)875 void ZlibContext::SetFlush(int flush) {
876 flush_ = flush;
877 }
878
879
GetAfterWriteOffsets(uint32_t* avail_in, uint32_t* avail_out) const880 void ZlibContext::GetAfterWriteOffsets(uint32_t* avail_in,
881 uint32_t* avail_out) const {
882 *avail_in = strm_.avail_in;
883 *avail_out = strm_.avail_out;
884 }
885
886
ErrorForMessage(const char* message) const887 CompressionError ZlibContext::ErrorForMessage(const char* message) const {
888 if (strm_.msg != nullptr)
889 message = strm_.msg;
890
891 return CompressionError { message, ZlibStrerror(err_), err_ };
892 }
893
894
GetErrorInfo() const895 CompressionError ZlibContext::GetErrorInfo() const {
896 // Acceptable error states depend on the type of zlib stream.
897 switch (err_) {
898 case Z_OK:
899 case Z_BUF_ERROR:
900 if (strm_.avail_out != 0 && flush_ == Z_FINISH) {
901 return ErrorForMessage("unexpected end of file");
902 }
903 case Z_STREAM_END:
904 // normal statuses, not fatal
905 break;
906 case Z_NEED_DICT:
907 if (dictionary_.empty())
908 return ErrorForMessage("Missing dictionary");
909 else
910 return ErrorForMessage("Bad dictionary");
911 default:
912 // something else.
913 return ErrorForMessage("Zlib error");
914 }
915
916 return CompressionError {};
917 }
918
919
ResetStream()920 CompressionError ZlibContext::ResetStream() {
921 bool first_init_call = InitZlib();
922 if (first_init_call && err_ != Z_OK) {
923 return ErrorForMessage("Failed to init stream before reset");
924 }
925
926 err_ = Z_OK;
927
928 switch (mode_) {
929 case DEFLATE:
930 case DEFLATERAW:
931 case GZIP:
932 err_ = deflateReset(&strm_);
933 break;
934 case INFLATE:
935 case INFLATERAW:
936 case GUNZIP:
937 err_ = inflateReset(&strm_);
938 break;
939 default:
940 break;
941 }
942
943 if (err_ != Z_OK)
944 return ErrorForMessage("Failed to reset stream");
945
946 return SetDictionary();
947 }
948
949
SetAllocationFunctions(alloc_func alloc, free_func free, void* opaque)950 void ZlibContext::SetAllocationFunctions(alloc_func alloc,
951 free_func free,
952 void* opaque) {
953 strm_.zalloc = alloc;
954 strm_.zfree = free;
955 strm_.opaque = opaque;
956 }
957
958
Init( int level, int window_bits, int mem_level, int strategy, std::vector<unsigned char>&& dictionary)959 void ZlibContext::Init(
960 int level, int window_bits, int mem_level, int strategy,
961 std::vector<unsigned char>&& dictionary) {
962 if (!((window_bits == 0) &&
963 (mode_ == INFLATE ||
964 mode_ == GUNZIP ||
965 mode_ == UNZIP))) {
966 CHECK(
967 (window_bits >= Z_MIN_WINDOWBITS && window_bits <= Z_MAX_WINDOWBITS) &&
968 "invalid windowBits");
969 }
970
971 CHECK((level >= Z_MIN_LEVEL && level <= Z_MAX_LEVEL) &&
972 "invalid compression level");
973
974 CHECK((mem_level >= Z_MIN_MEMLEVEL && mem_level <= Z_MAX_MEMLEVEL) &&
975 "invalid memlevel");
976
977 CHECK((strategy == Z_FILTERED || strategy == Z_HUFFMAN_ONLY ||
978 strategy == Z_RLE || strategy == Z_FIXED ||
979 strategy == Z_DEFAULT_STRATEGY) &&
980 "invalid strategy");
981
982 level_ = level;
983 window_bits_ = window_bits;
984 mem_level_ = mem_level;
985 strategy_ = strategy;
986
987 flush_ = Z_NO_FLUSH;
988
989 err_ = Z_OK;
990
991 if (mode_ == GZIP || mode_ == GUNZIP) {
992 window_bits_ += 16;
993 }
994
995 if (mode_ == UNZIP) {
996 window_bits_ += 32;
997 }
998
999 if (mode_ == DEFLATERAW || mode_ == INFLATERAW) {
1000 window_bits_ *= -1;
1001 }
1002
1003 dictionary_ = std::move(dictionary);
1004 }
1005
InitZlib()1006 bool ZlibContext::InitZlib() {
1007 Mutex::ScopedLock lock(mutex_);
1008 if (zlib_init_done_) {
1009 return false;
1010 }
1011
1012 switch (mode_) {
1013 case DEFLATE:
1014 case GZIP:
1015 case DEFLATERAW:
1016 err_ = deflateInit2(&strm_,
1017 level_,
1018 Z_DEFLATED,
1019 window_bits_,
1020 mem_level_,
1021 strategy_);
1022 break;
1023 case INFLATE:
1024 case GUNZIP:
1025 case INFLATERAW:
1026 case UNZIP:
1027 err_ = inflateInit2(&strm_, window_bits_);
1028 break;
1029 default:
1030 UNREACHABLE();
1031 }
1032
1033 if (err_ != Z_OK) {
1034 dictionary_.clear();
1035 mode_ = NONE;
1036 return true;
1037 }
1038
1039 SetDictionary();
1040 zlib_init_done_ = true;
1041 return true;
1042 }
1043
1044
SetDictionary()1045 CompressionError ZlibContext::SetDictionary() {
1046 if (dictionary_.empty())
1047 return CompressionError {};
1048
1049 err_ = Z_OK;
1050
1051 switch (mode_) {
1052 case DEFLATE:
1053 case DEFLATERAW:
1054 err_ = deflateSetDictionary(&strm_,
1055 dictionary_.data(),
1056 dictionary_.size());
1057 break;
1058 case INFLATERAW:
1059 // The other inflate cases will have the dictionary set when inflate()
1060 // returns Z_NEED_DICT in Process()
1061 err_ = inflateSetDictionary(&strm_,
1062 dictionary_.data(),
1063 dictionary_.size());
1064 break;
1065 default:
1066 break;
1067 }
1068
1069 if (err_ != Z_OK) {
1070 return ErrorForMessage("Failed to set dictionary");
1071 }
1072
1073 return CompressionError {};
1074 }
1075
1076
SetParams(int level, int strategy)1077 CompressionError ZlibContext::SetParams(int level, int strategy) {
1078 bool first_init_call = InitZlib();
1079 if (first_init_call && err_ != Z_OK) {
1080 return ErrorForMessage("Failed to init stream before set parameters");
1081 }
1082
1083 err_ = Z_OK;
1084
1085 switch (mode_) {
1086 case DEFLATE:
1087 case DEFLATERAW:
1088 err_ = deflateParams(&strm_, level, strategy);
1089 break;
1090 default:
1091 break;
1092 }
1093
1094 if (err_ != Z_OK && err_ != Z_BUF_ERROR) {
1095 return ErrorForMessage("Failed to set parameters");
1096 }
1097
1098 return CompressionError {};
1099 }
1100
1101
SetBuffers(const char* in, uint32_t in_len, char* out, uint32_t out_len)1102 void BrotliContext::SetBuffers(const char* in, uint32_t in_len,
1103 char* out, uint32_t out_len) {
1104 next_in_ = reinterpret_cast<const uint8_t*>(in);
1105 next_out_ = reinterpret_cast<uint8_t*>(out);
1106 avail_in_ = in_len;
1107 avail_out_ = out_len;
1108 }
1109
1110
SetFlush(int flush)1111 void BrotliContext::SetFlush(int flush) {
1112 flush_ = static_cast<BrotliEncoderOperation>(flush);
1113 }
1114
1115
GetAfterWriteOffsets(uint32_t* avail_in, uint32_t* avail_out) const1116 void BrotliContext::GetAfterWriteOffsets(uint32_t* avail_in,
1117 uint32_t* avail_out) const {
1118 *avail_in = avail_in_;
1119 *avail_out = avail_out_;
1120 }
1121
1122
DoThreadPoolWork()1123 void BrotliEncoderContext::DoThreadPoolWork() {
1124 CHECK_EQ(mode_, BROTLI_ENCODE);
1125 CHECK(state_);
1126 const uint8_t* next_in = next_in_;
1127 last_result_ = BrotliEncoderCompressStream(state_.get(),
1128 flush_,
1129 &avail_in_,
1130 &next_in,
1131 &avail_out_,
1132 &next_out_,
1133 nullptr);
1134 next_in_ += next_in - next_in_;
1135 }
1136
1137
Close()1138 void BrotliEncoderContext::Close() {
1139 state_.reset();
1140 mode_ = NONE;
1141 }
1142
Init(brotli_alloc_func alloc, brotli_free_func free, void* opaque)1143 CompressionError BrotliEncoderContext::Init(brotli_alloc_func alloc,
1144 brotli_free_func free,
1145 void* opaque) {
1146 alloc_ = alloc;
1147 free_ = free;
1148 alloc_opaque_ = opaque;
1149 state_.reset(BrotliEncoderCreateInstance(alloc, free, opaque));
1150 if (!state_) {
1151 return CompressionError("Could not initialize Brotli instance",
1152 "ERR_ZLIB_INITIALIZATION_FAILED",
1153 -1);
1154 } else {
1155 return CompressionError {};
1156 }
1157 }
1158
ResetStream()1159 CompressionError BrotliEncoderContext::ResetStream() {
1160 return Init(alloc_, free_, alloc_opaque_);
1161 }
1162
SetParams(int key, uint32_t value)1163 CompressionError BrotliEncoderContext::SetParams(int key, uint32_t value) {
1164 if (!BrotliEncoderSetParameter(state_.get(),
1165 static_cast<BrotliEncoderParameter>(key),
1166 value)) {
1167 return CompressionError("Setting parameter failed",
1168 "ERR_BROTLI_PARAM_SET_FAILED",
1169 -1);
1170 } else {
1171 return CompressionError {};
1172 }
1173 }
1174
GetErrorInfo() const1175 CompressionError BrotliEncoderContext::GetErrorInfo() const {
1176 if (!last_result_) {
1177 return CompressionError("Compression failed",
1178 "ERR_BROTLI_COMPRESSION_FAILED",
1179 -1);
1180 } else {
1181 return CompressionError {};
1182 }
1183 }
1184
1185
Close()1186 void BrotliDecoderContext::Close() {
1187 state_.reset();
1188 mode_ = NONE;
1189 }
1190
DoThreadPoolWork()1191 void BrotliDecoderContext::DoThreadPoolWork() {
1192 CHECK_EQ(mode_, BROTLI_DECODE);
1193 CHECK(state_);
1194 const uint8_t* next_in = next_in_;
1195 last_result_ = BrotliDecoderDecompressStream(state_.get(),
1196 &avail_in_,
1197 &next_in,
1198 &avail_out_,
1199 &next_out_,
1200 nullptr);
1201 next_in_ += next_in - next_in_;
1202 if (last_result_ == BROTLI_DECODER_RESULT_ERROR) {
1203 error_ = BrotliDecoderGetErrorCode(state_.get());
1204 error_string_ = std::string("ERR_") + BrotliDecoderErrorString(error_);
1205 }
1206 }
1207
Init(brotli_alloc_func alloc, brotli_free_func free, void* opaque)1208 CompressionError BrotliDecoderContext::Init(brotli_alloc_func alloc,
1209 brotli_free_func free,
1210 void* opaque) {
1211 alloc_ = alloc;
1212 free_ = free;
1213 alloc_opaque_ = opaque;
1214 state_.reset(BrotliDecoderCreateInstance(alloc, free, opaque));
1215 if (!state_) {
1216 return CompressionError("Could not initialize Brotli instance",
1217 "ERR_ZLIB_INITIALIZATION_FAILED",
1218 -1);
1219 } else {
1220 return CompressionError {};
1221 }
1222 }
1223
ResetStream()1224 CompressionError BrotliDecoderContext::ResetStream() {
1225 return Init(alloc_, free_, alloc_opaque_);
1226 }
1227
SetParams(int key, uint32_t value)1228 CompressionError BrotliDecoderContext::SetParams(int key, uint32_t value) {
1229 if (!BrotliDecoderSetParameter(state_.get(),
1230 static_cast<BrotliDecoderParameter>(key),
1231 value)) {
1232 return CompressionError("Setting parameter failed",
1233 "ERR_BROTLI_PARAM_SET_FAILED",
1234 -1);
1235 } else {
1236 return CompressionError {};
1237 }
1238 }
1239
GetErrorInfo() const1240 CompressionError BrotliDecoderContext::GetErrorInfo() const {
1241 if (error_ != BROTLI_DECODER_NO_ERROR) {
1242 return CompressionError("Decompression failed",
1243 error_string_.c_str(),
1244 static_cast<int>(error_));
1245 } else if (flush_ == BROTLI_OPERATION_FINISH &&
1246 last_result_ == BROTLI_DECODER_RESULT_NEEDS_MORE_INPUT) {
1247 // Match zlib's behaviour, as brotli doesn't have its own code for this.
1248 return CompressionError("unexpected end of file",
1249 "Z_BUF_ERROR",
1250 Z_BUF_ERROR);
1251 } else {
1252 return CompressionError {};
1253 }
1254 }
1255
1256
1257 template <typename Stream>
1258 struct MakeClass {
Makenode::__anon15438::MakeClass1259 static void Make(Environment* env, Local<Object> target, const char* name) {
1260 Isolate* isolate = env->isolate();
1261 Local<FunctionTemplate> z = NewFunctionTemplate(isolate, Stream::New);
1262
1263 z->InstanceTemplate()->SetInternalFieldCount(
1264 Stream::kInternalFieldCount);
1265 z->Inherit(AsyncWrap::GetConstructorTemplate(env));
1266
1267 SetProtoMethod(isolate, z, "write", Stream::template Write<true>);
1268 SetProtoMethod(isolate, z, "writeSync", Stream::template Write<false>);
1269 SetProtoMethod(isolate, z, "close", Stream::Close);
1270
1271 SetProtoMethod(isolate, z, "init", Stream::Init);
1272 SetProtoMethod(isolate, z, "params", Stream::Params);
1273 SetProtoMethod(isolate, z, "reset", Stream::Reset);
1274
1275 SetConstructorFunction(env->context(), target, name, z);
1276 }
1277
Makenode::__anon15438::MakeClass1278 static void Make(ExternalReferenceRegistry* registry) {
1279 registry->Register(Stream::New);
1280 registry->Register(Stream::template Write<true>);
1281 registry->Register(Stream::template Write<false>);
1282 registry->Register(Stream::Close);
1283 registry->Register(Stream::Init);
1284 registry->Register(Stream::Params);
1285 registry->Register(Stream::Reset);
1286 }
1287 };
1288
Initialize(Local<Object> target, Local<Value> unused, Local<Context> context, void* priv)1289 void Initialize(Local<Object> target,
1290 Local<Value> unused,
1291 Local<Context> context,
1292 void* priv) {
1293 Environment* env = Environment::GetCurrent(context);
1294
1295 MakeClass<ZlibStream>::Make(env, target, "Zlib");
1296 MakeClass<BrotliEncoderStream>::Make(env, target, "BrotliEncoder");
1297 MakeClass<BrotliDecoderStream>::Make(env, target, "BrotliDecoder");
1298
1299 target->Set(env->context(),
1300 FIXED_ONE_BYTE_STRING(env->isolate(), "ZLIB_VERSION"),
1301 FIXED_ONE_BYTE_STRING(env->isolate(), ZLIB_VERSION)).Check();
1302 }
1303
RegisterExternalReferences(ExternalReferenceRegistry* registry)1304 void RegisterExternalReferences(ExternalReferenceRegistry* registry) {
1305 MakeClass<ZlibStream>::Make(registry);
1306 MakeClass<BrotliEncoderStream>::Make(registry);
1307 MakeClass<BrotliDecoderStream>::Make(registry);
1308 }
1309
1310 } // anonymous namespace
1311
DefineZlibConstants(Local<Object> target)1312 void DefineZlibConstants(Local<Object> target) {
1313 NODE_DEFINE_CONSTANT(target, Z_NO_FLUSH);
1314 NODE_DEFINE_CONSTANT(target, Z_PARTIAL_FLUSH);
1315 NODE_DEFINE_CONSTANT(target, Z_SYNC_FLUSH);
1316 NODE_DEFINE_CONSTANT(target, Z_FULL_FLUSH);
1317 NODE_DEFINE_CONSTANT(target, Z_FINISH);
1318 NODE_DEFINE_CONSTANT(target, Z_BLOCK);
1319
1320 // return/error codes
1321 NODE_DEFINE_CONSTANT(target, Z_OK);
1322 NODE_DEFINE_CONSTANT(target, Z_STREAM_END);
1323 NODE_DEFINE_CONSTANT(target, Z_NEED_DICT);
1324 NODE_DEFINE_CONSTANT(target, Z_ERRNO);
1325 NODE_DEFINE_CONSTANT(target, Z_STREAM_ERROR);
1326 NODE_DEFINE_CONSTANT(target, Z_DATA_ERROR);
1327 NODE_DEFINE_CONSTANT(target, Z_MEM_ERROR);
1328 NODE_DEFINE_CONSTANT(target, Z_BUF_ERROR);
1329 NODE_DEFINE_CONSTANT(target, Z_VERSION_ERROR);
1330
1331 NODE_DEFINE_CONSTANT(target, Z_NO_COMPRESSION);
1332 NODE_DEFINE_CONSTANT(target, Z_BEST_SPEED);
1333 NODE_DEFINE_CONSTANT(target, Z_BEST_COMPRESSION);
1334 NODE_DEFINE_CONSTANT(target, Z_DEFAULT_COMPRESSION);
1335 NODE_DEFINE_CONSTANT(target, Z_FILTERED);
1336 NODE_DEFINE_CONSTANT(target, Z_HUFFMAN_ONLY);
1337 NODE_DEFINE_CONSTANT(target, Z_RLE);
1338 NODE_DEFINE_CONSTANT(target, Z_FIXED);
1339 NODE_DEFINE_CONSTANT(target, Z_DEFAULT_STRATEGY);
1340 NODE_DEFINE_CONSTANT(target, ZLIB_VERNUM);
1341
1342 NODE_DEFINE_CONSTANT(target, DEFLATE);
1343 NODE_DEFINE_CONSTANT(target, INFLATE);
1344 NODE_DEFINE_CONSTANT(target, GZIP);
1345 NODE_DEFINE_CONSTANT(target, GUNZIP);
1346 NODE_DEFINE_CONSTANT(target, DEFLATERAW);
1347 NODE_DEFINE_CONSTANT(target, INFLATERAW);
1348 NODE_DEFINE_CONSTANT(target, UNZIP);
1349 NODE_DEFINE_CONSTANT(target, BROTLI_DECODE);
1350 NODE_DEFINE_CONSTANT(target, BROTLI_ENCODE);
1351
1352 NODE_DEFINE_CONSTANT(target, Z_MIN_WINDOWBITS);
1353 NODE_DEFINE_CONSTANT(target, Z_MAX_WINDOWBITS);
1354 NODE_DEFINE_CONSTANT(target, Z_DEFAULT_WINDOWBITS);
1355 NODE_DEFINE_CONSTANT(target, Z_MIN_CHUNK);
1356 NODE_DEFINE_CONSTANT(target, Z_MAX_CHUNK);
1357 NODE_DEFINE_CONSTANT(target, Z_DEFAULT_CHUNK);
1358 NODE_DEFINE_CONSTANT(target, Z_MIN_MEMLEVEL);
1359 NODE_DEFINE_CONSTANT(target, Z_MAX_MEMLEVEL);
1360 NODE_DEFINE_CONSTANT(target, Z_DEFAULT_MEMLEVEL);
1361 NODE_DEFINE_CONSTANT(target, Z_MIN_LEVEL);
1362 NODE_DEFINE_CONSTANT(target, Z_MAX_LEVEL);
1363 NODE_DEFINE_CONSTANT(target, Z_DEFAULT_LEVEL);
1364
1365 // Brotli constants
1366 NODE_DEFINE_CONSTANT(target, BROTLI_OPERATION_PROCESS);
1367 NODE_DEFINE_CONSTANT(target, BROTLI_OPERATION_FLUSH);
1368 NODE_DEFINE_CONSTANT(target, BROTLI_OPERATION_FINISH);
1369 NODE_DEFINE_CONSTANT(target, BROTLI_OPERATION_EMIT_METADATA);
1370 NODE_DEFINE_CONSTANT(target, BROTLI_PARAM_MODE);
1371 NODE_DEFINE_CONSTANT(target, BROTLI_MODE_GENERIC);
1372 NODE_DEFINE_CONSTANT(target, BROTLI_MODE_TEXT);
1373 NODE_DEFINE_CONSTANT(target, BROTLI_MODE_FONT);
1374 NODE_DEFINE_CONSTANT(target, BROTLI_DEFAULT_MODE);
1375 NODE_DEFINE_CONSTANT(target, BROTLI_PARAM_QUALITY);
1376 NODE_DEFINE_CONSTANT(target, BROTLI_MIN_QUALITY);
1377 NODE_DEFINE_CONSTANT(target, BROTLI_MAX_QUALITY);
1378 NODE_DEFINE_CONSTANT(target, BROTLI_DEFAULT_QUALITY);
1379 NODE_DEFINE_CONSTANT(target, BROTLI_PARAM_LGWIN);
1380 NODE_DEFINE_CONSTANT(target, BROTLI_MIN_WINDOW_BITS);
1381 NODE_DEFINE_CONSTANT(target, BROTLI_MAX_WINDOW_BITS);
1382 NODE_DEFINE_CONSTANT(target, BROTLI_LARGE_MAX_WINDOW_BITS);
1383 NODE_DEFINE_CONSTANT(target, BROTLI_DEFAULT_WINDOW);
1384 NODE_DEFINE_CONSTANT(target, BROTLI_PARAM_LGBLOCK);
1385 NODE_DEFINE_CONSTANT(target, BROTLI_MIN_INPUT_BLOCK_BITS);
1386 NODE_DEFINE_CONSTANT(target, BROTLI_MAX_INPUT_BLOCK_BITS);
1387 NODE_DEFINE_CONSTANT(target, BROTLI_PARAM_DISABLE_LITERAL_CONTEXT_MODELING);
1388 NODE_DEFINE_CONSTANT(target, BROTLI_PARAM_SIZE_HINT);
1389 NODE_DEFINE_CONSTANT(target, BROTLI_PARAM_LARGE_WINDOW);
1390 NODE_DEFINE_CONSTANT(target, BROTLI_PARAM_NPOSTFIX);
1391 NODE_DEFINE_CONSTANT(target, BROTLI_PARAM_NDIRECT);
1392 NODE_DEFINE_CONSTANT(target, BROTLI_DECODER_RESULT_ERROR);
1393 NODE_DEFINE_CONSTANT(target, BROTLI_DECODER_RESULT_SUCCESS);
1394 NODE_DEFINE_CONSTANT(target, BROTLI_DECODER_RESULT_NEEDS_MORE_INPUT);
1395 NODE_DEFINE_CONSTANT(target, BROTLI_DECODER_RESULT_NEEDS_MORE_OUTPUT);
1396 NODE_DEFINE_CONSTANT(target,
1397 BROTLI_DECODER_PARAM_DISABLE_RING_BUFFER_REALLOCATION);
1398 NODE_DEFINE_CONSTANT(target, BROTLI_DECODER_PARAM_LARGE_WINDOW);
1399 NODE_DEFINE_CONSTANT(target, BROTLI_DECODER_NO_ERROR);
1400 NODE_DEFINE_CONSTANT(target, BROTLI_DECODER_SUCCESS);
1401 NODE_DEFINE_CONSTANT(target, BROTLI_DECODER_NEEDS_MORE_INPUT);
1402 NODE_DEFINE_CONSTANT(target, BROTLI_DECODER_NEEDS_MORE_OUTPUT);
1403 NODE_DEFINE_CONSTANT(target, BROTLI_DECODER_ERROR_FORMAT_EXUBERANT_NIBBLE);
1404 NODE_DEFINE_CONSTANT(target, BROTLI_DECODER_ERROR_FORMAT_RESERVED);
1405 NODE_DEFINE_CONSTANT(target,
1406 BROTLI_DECODER_ERROR_FORMAT_EXUBERANT_META_NIBBLE);
1407 NODE_DEFINE_CONSTANT(target,
1408 BROTLI_DECODER_ERROR_FORMAT_SIMPLE_HUFFMAN_ALPHABET);
1409 NODE_DEFINE_CONSTANT(target, BROTLI_DECODER_ERROR_FORMAT_SIMPLE_HUFFMAN_SAME);
1410 NODE_DEFINE_CONSTANT(target, BROTLI_DECODER_ERROR_FORMAT_CL_SPACE);
1411 NODE_DEFINE_CONSTANT(target, BROTLI_DECODER_ERROR_FORMAT_HUFFMAN_SPACE);
1412 NODE_DEFINE_CONSTANT(target, BROTLI_DECODER_ERROR_FORMAT_CONTEXT_MAP_REPEAT);
1413 NODE_DEFINE_CONSTANT(target, BROTLI_DECODER_ERROR_FORMAT_BLOCK_LENGTH_1);
1414 NODE_DEFINE_CONSTANT(target, BROTLI_DECODER_ERROR_FORMAT_BLOCK_LENGTH_2);
1415 NODE_DEFINE_CONSTANT(target, BROTLI_DECODER_ERROR_FORMAT_TRANSFORM);
1416 NODE_DEFINE_CONSTANT(target, BROTLI_DECODER_ERROR_FORMAT_DICTIONARY);
1417 NODE_DEFINE_CONSTANT(target, BROTLI_DECODER_ERROR_FORMAT_WINDOW_BITS);
1418 NODE_DEFINE_CONSTANT(target, BROTLI_DECODER_ERROR_FORMAT_PADDING_1);
1419 NODE_DEFINE_CONSTANT(target, BROTLI_DECODER_ERROR_FORMAT_PADDING_2);
1420 NODE_DEFINE_CONSTANT(target, BROTLI_DECODER_ERROR_FORMAT_DISTANCE);
1421 NODE_DEFINE_CONSTANT(target, BROTLI_DECODER_ERROR_DICTIONARY_NOT_SET);
1422 NODE_DEFINE_CONSTANT(target, BROTLI_DECODER_ERROR_INVALID_ARGUMENTS);
1423 NODE_DEFINE_CONSTANT(target, BROTLI_DECODER_ERROR_ALLOC_CONTEXT_MODES);
1424 NODE_DEFINE_CONSTANT(target, BROTLI_DECODER_ERROR_ALLOC_TREE_GROUPS);
1425 NODE_DEFINE_CONSTANT(target, BROTLI_DECODER_ERROR_ALLOC_CONTEXT_MAP);
1426 NODE_DEFINE_CONSTANT(target, BROTLI_DECODER_ERROR_ALLOC_RING_BUFFER_1);
1427 NODE_DEFINE_CONSTANT(target, BROTLI_DECODER_ERROR_ALLOC_RING_BUFFER_2);
1428 NODE_DEFINE_CONSTANT(target, BROTLI_DECODER_ERROR_ALLOC_BLOCK_TYPE_TREES);
1429 NODE_DEFINE_CONSTANT(target, BROTLI_DECODER_ERROR_UNREACHABLE);
1430 }
1431
1432 } // namespace node
1433
1434 NODE_BINDING_CONTEXT_AWARE_INTERNAL(zlib, node::Initialize)
1435 NODE_BINDING_EXTERNAL_REFERENCE(zlib, node::RegisterExternalReferences)
1436