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