• 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::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