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