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