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