38 #include <sys/types.h> 44 using v8::FunctionCallbackInfo;
45 using v8::FunctionTemplate;
46 using v8::HandleScope;
67 #define GZIP_HEADER_ID1 0x1f 68 #define GZIP_HEADER_ID2 0x8b 73 class ZCtx :
public AsyncWrap {
75 ZCtx(Environment* env, Local<Object>
wrap, node_zlib_mode mode)
76 : AsyncWrap(env, wrap, AsyncWrap::PROVIDER_ZLIB),
87 write_in_progress_(
false),
88 pending_close_(
false),
90 gzip_id_bytes_read_(0) {
97 CHECK_EQ(
false, write_in_progress_ &&
"write in progress");
102 if (write_in_progress_) {
103 pending_close_ =
true;
107 pending_close_ =
false;
108 CHECK(init_done_ &&
"close before init");
109 CHECK_LE(mode_, UNZIP);
111 if (mode_ == DEFLATE || mode_ == GZIP || mode_ == DEFLATERAW) {
112 (void)deflateEnd(&strm_);
113 int64_t change_in_bytes = -
static_cast<int64_t
>(kDeflateContextSize);
114 env()->isolate()->AdjustAmountOfExternalAllocatedMemory(change_in_bytes);
115 }
else if (mode_ == INFLATE || mode_ == GUNZIP || mode_ == INFLATERAW ||
117 (void)inflateEnd(&strm_);
118 int64_t change_in_bytes = -
static_cast<int64_t
>(kInflateContextSize);
119 env()->isolate()->AdjustAmountOfExternalAllocatedMemory(change_in_bytes);
123 if (dictionary_ !=
nullptr) {
124 delete[] dictionary_;
125 dictionary_ =
nullptr;
130 static void Close(
const FunctionCallbackInfo<Value>& args) {
132 ASSIGN_OR_RETURN_UNWRAP(&ctx, args.Holder());
138 template <
bool async>
139 static void Write(
const FunctionCallbackInfo<Value>& args) {
140 CHECK_EQ(args.Length(), 7);
143 ASSIGN_OR_RETURN_UNWRAP(&ctx, args.Holder());
144 CHECK(ctx->init_done_ &&
"write before init");
145 CHECK(ctx->mode_ != NONE &&
"already finalized");
147 CHECK_EQ(
false, ctx->write_in_progress_ &&
"write already in progress");
148 CHECK_EQ(
false, ctx->pending_close_ &&
"close is pending");
149 ctx->write_in_progress_ =
true;
152 CHECK_EQ(
false, args[0]->IsUndefined() &&
"must provide flush value");
154 unsigned int flush = args[0]->Uint32Value();
156 if (flush != Z_NO_FLUSH &&
157 flush != Z_PARTIAL_FLUSH &&
158 flush != Z_SYNC_FLUSH &&
159 flush != Z_FULL_FLUSH &&
162 CHECK(0 &&
"Invalid flush value");
167 size_t in_off, in_len, out_off, out_len;
168 Environment* env = ctx->env();
170 if (args[1]->IsNull()) {
177 Local<Object> in_buf;
178 in_buf = args[1]->ToObject(env->isolate());
179 in_off = args[2]->Uint32Value();
180 in_len = args[3]->Uint32Value();
182 CHECK(Buffer::IsWithinBounds(in_off, in_len,
Buffer::Length(in_buf)));
183 in =
reinterpret_cast<Bytef *
>(
Buffer::Data(in_buf) + in_off);
187 Local<Object> out_buf = args[4]->ToObject(env->isolate());
188 out_off = args[5]->Uint32Value();
189 out_len = args[6]->Uint32Value();
190 CHECK(Buffer::IsWithinBounds(out_off, out_len,
Buffer::Length(out_buf)));
191 out =
reinterpret_cast<Bytef *
>(
Buffer::Data(out_buf) + out_off);
194 uv_work_t* work_req = &(ctx->work_req_);
196 ctx->strm_.avail_in = in_len;
197 ctx->strm_.next_in = in;
198 ctx->strm_.avail_out = out_len;
199 ctx->strm_.next_out = out;
204 ctx->env()->PrintSyncTrace();
207 AfterSync(ctx, args);
212 uv_queue_work(ctx->env()->event_loop(),
217 args.GetReturnValue().Set(ctx->object());
221 static void AfterSync(ZCtx*
ctx,
const FunctionCallbackInfo<Value>& args) {
222 Environment* env = ctx->env();
224 ctx->strm_.avail_out);
226 ctx->strm_.avail_in);
228 ctx->write_in_progress_ =
false;
230 Local<Array> result =
Array::New(env->isolate(), 2);
231 result->Set(0, avail_in);
232 result->Set(1, avail_out);
233 args.GetReturnValue().Set(result);
243 static void Process(uv_work_t* work_req) {
244 ZCtx *ctx = ContainerOf(&ZCtx::work_req_, work_req);
246 const Bytef* next_expected_header_byte =
nullptr;
251 switch (ctx->mode_) {
255 ctx->err_ = deflate(&ctx->strm_, ctx->flush_);
258 if (ctx->strm_.avail_in > 0) {
259 next_expected_header_byte = ctx->strm_.next_in;
262 switch (ctx->gzip_id_bytes_read_) {
264 if (next_expected_header_byte ==
nullptr) {
269 ctx->gzip_id_bytes_read_ = 1;
270 next_expected_header_byte++;
272 if (ctx->strm_.avail_in == 1) {
277 ctx->mode_ = INFLATE;
283 if (next_expected_header_byte ==
nullptr) {
288 ctx->gzip_id_bytes_read_ = 2;
293 ctx->mode_ = INFLATE;
298 CHECK(0 &&
"invalid number of gzip magic number bytes read");
305 ctx->err_ = inflate(&ctx->strm_, ctx->flush_);
309 if (ctx->mode_ != INFLATERAW &&
310 ctx->err_ == Z_NEED_DICT &&
311 ctx->dictionary_ !=
nullptr) {
313 ctx->err_ = inflateSetDictionary(&ctx->strm_,
315 ctx->dictionary_len_);
316 if (ctx->err_ == Z_OK) {
318 ctx->err_ = inflate(&ctx->strm_, ctx->flush_);
319 }
else if (ctx->err_ == Z_DATA_ERROR) {
323 ctx->err_ = Z_NEED_DICT;
327 while (ctx->strm_.avail_in > 0 &&
328 ctx->mode_ == GUNZIP &&
329 ctx->err_ == Z_STREAM_END &&
330 ctx->strm_.next_in[0] != 0x00) {
337 ctx->err_ = inflate(&ctx->strm_, ctx->flush_);
352 static bool CheckError(ZCtx* ctx) {
357 if (ctx->strm_.avail_out != 0 && ctx->flush_ == Z_FINISH) {
358 ZCtx::Error(ctx,
"unexpected end of file");
365 if (ctx->dictionary_ ==
nullptr)
366 ZCtx::Error(ctx,
"Missing dictionary");
368 ZCtx::Error(ctx,
"Bad dictionary");
372 ZCtx::Error(ctx,
"Zlib error");
381 static void After(uv_work_t* work_req,
int status) {
384 ZCtx* ctx = ContainerOf(&ZCtx::work_req_, work_req);
385 Environment* env = ctx->env();
387 HandleScope handle_scope(env->isolate());
388 Context::Scope context_scope(env->context());
390 if (!CheckError(ctx))
394 ctx->strm_.avail_out);
396 ctx->strm_.avail_in);
398 ctx->write_in_progress_ =
false;
401 Local<Value> args[2] = { avail_in, avail_out };
402 ctx->MakeCallback(env->callback_string(), arraysize(args), args);
405 if (ctx->pending_close_)
409 static void Error(ZCtx* ctx,
const char* message) {
410 Environment* env = ctx->env();
413 CHECK_EQ(env->context(), env->isolate()->GetCurrentContext());
415 if (ctx->strm_.msg !=
nullptr) {
416 message = ctx->strm_.msg;
419 HandleScope scope(env->isolate());
420 Local<Value> args[2] = {
421 OneByteString(env->isolate(), message),
424 ctx->MakeCallback(env->onerror_string(), arraysize(args), args);
427 if (ctx->write_in_progress_)
429 ctx->write_in_progress_ =
false;
430 if (ctx->pending_close_)
434 static void New(
const FunctionCallbackInfo<Value>& args) {
435 Environment* env = Environment::GetCurrent(args);
437 if (args.Length() < 1 || !args[0]->IsInt32()) {
438 return env->ThrowTypeError(
"Bad argument");
440 node_zlib_mode mode =
static_cast<node_zlib_mode
>(args[0]->Int32Value());
442 if (mode < DEFLATE || mode > UNZIP) {
443 return env->ThrowTypeError(
"Bad argument");
446 new ZCtx(env, args.This(), mode);
450 static void Init(
const FunctionCallbackInfo<Value>& args) {
451 CHECK((args.Length() == 4 || args.Length() == 5) &&
452 "init(windowBits, level, memLevel, strategy, [dictionary])");
455 ASSIGN_OR_RETURN_UNWRAP(&ctx, args.Holder());
457 int windowBits = args[0]->Uint32Value();
458 CHECK((windowBits >= 8 && windowBits <= 15) &&
"invalid windowBits");
460 int level = args[1]->Int32Value();
461 CHECK((level >= -1 && level <= 9) &&
"invalid compression level");
463 int memLevel = args[2]->Uint32Value();
464 CHECK((memLevel >= 1 && memLevel <= 9) &&
"invalid memlevel");
466 int strategy = args[3]->Uint32Value();
467 CHECK((strategy == Z_FILTERED ||
468 strategy == Z_HUFFMAN_ONLY ||
470 strategy == Z_FIXED ||
471 strategy == Z_DEFAULT_STRATEGY) &&
"invalid strategy");
473 char* dictionary =
nullptr;
474 size_t dictionary_len = 0;
476 Local<Object> dictionary_ = args[4]->ToObject(args.GetIsolate());
479 dictionary =
new char[dictionary_len];
481 memcpy(dictionary,
Buffer::Data(dictionary_), dictionary_len);
484 Init(ctx, level, windowBits, memLevel, strategy,
485 dictionary, dictionary_len);
489 static void Params(
const FunctionCallbackInfo<Value>& args) {
490 CHECK(args.Length() == 2 &&
"params(level, strategy)");
492 ASSIGN_OR_RETURN_UNWRAP(&ctx, args.Holder());
493 Params(ctx, args[0]->Int32Value(), args[1]->Int32Value());
496 static void Reset(
const FunctionCallbackInfo<Value> &args) {
498 ASSIGN_OR_RETURN_UNWRAP(&ctx, args.Holder());
503 static void Init(ZCtx *ctx,
int level,
int windowBits,
int memLevel,
504 int strategy,
char* dictionary,
size_t dictionary_len) {
506 ctx->windowBits_ = windowBits;
507 ctx->memLevel_ = memLevel;
508 ctx->strategy_ = strategy;
510 ctx->strm_.zalloc = Z_NULL;
511 ctx->strm_.zfree = Z_NULL;
512 ctx->strm_.opaque = Z_NULL;
514 ctx->flush_ = Z_NO_FLUSH;
518 if (ctx->mode_ == GZIP || ctx->mode_ == GUNZIP) {
519 ctx->windowBits_ += 16;
522 if (ctx->mode_ == UNZIP) {
523 ctx->windowBits_ += 32;
526 if (ctx->mode_ == DEFLATERAW || ctx->mode_ == INFLATERAW) {
527 ctx->windowBits_ *= -1;
530 switch (ctx->mode_) {
534 ctx->err_ = deflateInit2(&ctx->strm_,
540 ctx->env()->isolate()
541 ->AdjustAmountOfExternalAllocatedMemory(kDeflateContextSize);
547 ctx->err_ = inflateInit2(&ctx->strm_, ctx->windowBits_);
548 ctx->env()->isolate()
549 ->AdjustAmountOfExternalAllocatedMemory(kInflateContextSize);
555 ctx->dictionary_ =
reinterpret_cast<Bytef *
>(dictionary);
556 ctx->dictionary_len_ = dictionary_len;
558 ctx->write_in_progress_ =
false;
559 ctx->init_done_ =
true;
561 if (ctx->err_ != Z_OK) {
562 if (dictionary !=
nullptr) {
564 ctx->dictionary_ =
nullptr;
567 ctx->env()->ThrowError(
"Init error");
571 static void SetDictionary(ZCtx* ctx) {
572 if (ctx->dictionary_ ==
nullptr)
577 switch (ctx->mode_) {
580 ctx->err_ = deflateSetDictionary(&ctx->strm_,
582 ctx->dictionary_len_);
587 ctx->err_ = inflateSetDictionary(&ctx->strm_,
589 ctx->dictionary_len_);
595 if (ctx->err_ != Z_OK) {
596 ZCtx::Error(ctx,
"Failed to set dictionary");
600 static void Params(ZCtx* ctx,
int level,
int strategy) {
603 switch (ctx->mode_) {
606 ctx->err_ = deflateParams(&ctx->strm_, level, strategy);
612 if (ctx->err_ != Z_OK && ctx->err_ != Z_BUF_ERROR) {
613 ZCtx::Error(ctx,
"Failed to set parameters");
617 static void Reset(ZCtx* ctx) {
620 switch (ctx->mode_) {
624 ctx->err_ = deflateReset(&ctx->strm_);
629 ctx->err_ = inflateReset(&ctx->strm_);
635 if (ctx->err_ != Z_OK) {
636 ZCtx::Error(ctx,
"Failed to reset stream");
640 size_t self_size()
const override {
return sizeof(*this); }
652 MakeWeak<ZCtx>(
this);
656 static const int kDeflateContextSize = 16384;
657 static const int kInflateContextSize = 10240;
660 size_t dictionary_len_;
666 node_zlib_mode mode_;
671 bool write_in_progress_;
674 unsigned int gzip_id_bytes_read_;
678 void InitZlib(Local<Object> target,
680 Local<Context> context,
682 Environment* env = Environment::GetCurrent(context);
683 Local<FunctionTemplate> z = env->NewFunctionTemplate(
ZCtx::New);
685 z->InstanceTemplate()->SetInternalFieldCount(1);
687 AsyncWrap::AddWrapMethods(env, z);
688 env->SetProtoMethod(z,
"write", ZCtx::Write<true>);
689 env->SetProtoMethod(z,
"writeSync", ZCtx::Write<false>);
691 env->SetProtoMethod(z,
"close", ZCtx::Close);
692 env->SetProtoMethod(z,
"params", ZCtx::Params);
693 env->SetProtoMethod(z,
"reset", ZCtx::Reset);
695 Local<String> zlibString = FIXED_ONE_BYTE_STRING(env->isolate(),
"Zlib");
696 z->SetClassName(zlibString);
697 target->Set(zlibString, z->GetFunction());
699 target->Set(FIXED_ONE_BYTE_STRING(env->isolate(),
"ZLIB_VERSION"),
700 FIXED_ONE_BYTE_STRING(env->isolate(), ZLIB_VERSION));
bool HasInstance(Local< Value > val)
NODE_MODULE_CONTEXT_AWARE_BUILTIN(inspector, node::inspector::Agent::InitInspector)
size_t Length(Local< Value > val)
char * Data(Local< Value > val)
MaybeLocal< Object > New(Isolate *isolate, Local< String > string, enum encoding enc)
void Init(int *argc, const char **argv, int *exec_argc, const char ***exec_argv)