GCC Code Coverage Report
Directory: ../ Exec Total Coverage
File: /home/node-core-coverage/node-core-coverage/workdir/node/out/../src/node_zlib.cc Lines: 264 274 96.4 %
Date: 2016-09-05 Branches: 153 227 67.4 %

Line Branch Exec Source
1
#include "node.h"
2
#include "node_buffer.h"
3
4
#include "async-wrap.h"
5
#include "async-wrap-inl.h"
6
#include "env.h"
7
#include "env-inl.h"
8
#include "util.h"
9
#include "util-inl.h"
10
11
#include "v8.h"
12
#include "zlib.h"
13
14
#include <errno.h>
15
#include <stdlib.h>
16
#include <string.h>
17
#include <sys/types.h>
18
19
namespace node {
20
21
using v8::Array;
22
using v8::Context;
23
using v8::FunctionCallbackInfo;
24
using v8::FunctionTemplate;
25
using v8::HandleScope;
26
using v8::Integer;
27
using v8::Local;
28
using v8::Number;
29
using v8::Object;
30
using v8::Value;
31
32
enum node_zlib_mode {
33
  NONE,
34
  DEFLATE,
35
  INFLATE,
36
  GZIP,
37
  GUNZIP,
38
  DEFLATERAW,
39
  INFLATERAW,
40
  UNZIP
41
};
42
43
#define GZIP_HEADER_ID1 0x1f
44
#define GZIP_HEADER_ID2 0x8b
45
46
void InitZlib(v8::Local<v8::Object> target);
47
48
49
/**
50
 * Deflate/Inflate
51
 */
52
class ZCtx : public AsyncWrap {
53
 public:
54
176
  ZCtx(Environment* env, Local<Object> wrap, node_zlib_mode mode)
55
      : AsyncWrap(env, wrap, AsyncWrap::PROVIDER_ZLIB),
56
        dictionary_(nullptr),
57
        dictionary_len_(0),
58
        err_(0),
59
        flush_(0),
60
        init_done_(false),
61
        level_(0),
62
        memLevel_(0),
63
        mode_(mode),
64
        strategy_(0),
65
        windowBits_(0),
66
        write_in_progress_(false),
67
        pending_close_(false),
68
        refs_(0),
69
176
        gzip_id_bytes_read_(0) {
70
176
    MakeWeak<ZCtx>(this);
71
176
  }
72
73
74
459
  ~ZCtx() override {
75
153
    CHECK_EQ(false, write_in_progress_ && "write in progress");
76
153
    Close();
77
306
  }
78
79
336
  void Close() {
80
336
    if (write_in_progress_) {
81
24
      pending_close_ = true;
82
24
      return;
83
    }
84
85
312
    pending_close_ = false;
86
312
    CHECK(init_done_ && "close before init");
87
312
    CHECK_LE(mode_, UNZIP);
88
89

312
    if (mode_ == DEFLATE || mode_ == GZIP || mode_ == DEFLATERAW) {
90
58
      (void)deflateEnd(&strm_);
91
58
      int64_t change_in_bytes = -static_cast<int64_t>(kDeflateContextSize);
92
58
      env()->isolate()->AdjustAmountOfExternalAllocatedMemory(change_in_bytes);
93


254
    } else if (mode_ == INFLATE || mode_ == GUNZIP || mode_ == INFLATERAW ||
94
               mode_ == UNZIP) {
95
101
      (void)inflateEnd(&strm_);
96
101
      int64_t change_in_bytes = -static_cast<int64_t>(kInflateContextSize);
97
101
      env()->isolate()->AdjustAmountOfExternalAllocatedMemory(change_in_bytes);
98
    }
99
312
    mode_ = NONE;
100
101
312
    if (dictionary_ != nullptr) {
102
5
      delete[] dictionary_;
103
5
      dictionary_ = nullptr;
104
    }
105
  }
106
107
108
159
  static void Close(const FunctionCallbackInfo<Value>& args) {
109
    ZCtx* ctx;
110
159
    ASSIGN_OR_RETURN_UNWRAP(&ctx, args.Holder());
111
159
    ctx->Close();
112
  }
113
114
115
  // write(flush, in, in_off, in_len, out, out_off, out_len)
116
  template <bool async>
117
761
  static void Write(const FunctionCallbackInfo<Value>& args) {
118

761
    CHECK_EQ(args.Length(), 7);
119
120
    ZCtx* ctx;
121

817
    ASSIGN_OR_RETURN_UNWRAP(&ctx, args.Holder());
122

761
    CHECK(ctx->init_done_ && "write before init");
123

761
    CHECK(ctx->mode_ != NONE && "already finalized");
124
125

761
    CHECK_EQ(false, ctx->write_in_progress_ && "write already in progress");
126

761
    CHECK_EQ(false, ctx->pending_close_ && "close is pending");
127
761
    ctx->write_in_progress_ = true;
128
1522
    ctx->Ref();
129
130


2283
    CHECK_EQ(false, args[0]->IsUndefined() && "must provide flush value");
131
132
761
    unsigned int flush = args[0]->Uint32Value();
133
134

761
    if (flush != Z_NO_FLUSH &&
135
        flush != Z_PARTIAL_FLUSH &&
136
        flush != Z_SYNC_FLUSH &&
137
        flush != Z_FULL_FLUSH &&
138
        flush != Z_FINISH &&
139
        flush != Z_BLOCK) {
140
      CHECK(0 && "Invalid flush value");
141
    }
142
143
    Bytef *in;
144
    Bytef *out;
145
    size_t in_off, in_len, out_off, out_len;
146
761
    Environment* env = ctx->env();
147
148

1522
    if (args[1]->IsNull()) {
149
      // just a flush
150
      in = nullptr;
151
      in_len = 0;
152
      in_off = 0;
153
    } else {
154

761
      CHECK(Buffer::HasInstance(args[1]));
155
761
      Local<Object> in_buf;
156
1522
      in_buf = args[1]->ToObject(env->isolate());
157
761
      in_off = args[2]->Uint32Value();
158
761
      in_len = args[3]->Uint32Value();
159
160

1522
      CHECK(Buffer::IsWithinBounds(in_off, in_len, Buffer::Length(in_buf)));
161
761
      in = reinterpret_cast<Bytef *>(Buffer::Data(in_buf) + in_off);
162
    }
163
164

761
    CHECK(Buffer::HasInstance(args[4]));
165
1522
    Local<Object> out_buf = args[4]->ToObject(env->isolate());
166
761
    out_off = args[5]->Uint32Value();
167
761
    out_len = args[6]->Uint32Value();
168

1522
    CHECK(Buffer::IsWithinBounds(out_off, out_len, Buffer::Length(out_buf)));
169
761
    out = reinterpret_cast<Bytef *>(Buffer::Data(out_buf) + out_off);
170
171
    // build up the work request
172
761
    uv_work_t* work_req = &(ctx->work_req_);
173
174
761
    ctx->strm_.avail_in = in_len;
175
761
    ctx->strm_.next_in = in;
176
761
    ctx->strm_.avail_out = out_len;
177
761
    ctx->strm_.next_out = out;
178
761
    ctx->flush_ = flush;
179
180
    if (!async) {
181
      // sync version
182
56
      ctx->env()->PrintSyncTrace();
183
56
      Process(work_req);
184
56
      if (CheckError(ctx))
185
50
        AfterSync(ctx, args);
186
      return;
187
    }
188
189
    // async version
190
705
    uv_queue_work(ctx->env()->event_loop(),
191
                  work_req,
192
                  ZCtx::Process,
193
                  ZCtx::After);
194
195
2820
    args.GetReturnValue().Set(ctx->object());
196
  }
197
198
199
50
  static void AfterSync(ZCtx* ctx, const FunctionCallbackInfo<Value>& args) {
200
50
    Environment* env = ctx->env();
201
    Local<Integer> avail_out = Integer::New(env->isolate(),
202
50
                                            ctx->strm_.avail_out);
203
    Local<Integer> avail_in = Integer::New(env->isolate(),
204
50
                                           ctx->strm_.avail_in);
205
206
50
    ctx->write_in_progress_ = false;
207
208
50
    Local<Array> result = Array::New(env->isolate(), 2);
209
50
    result->Set(0, avail_in);
210
50
    result->Set(1, avail_out);
211
100
    args.GetReturnValue().Set(result);
212
213
50
    ctx->Unref();
214
50
  }
215
216
217
  // thread pool!
218
  // This function may be called multiple times on the uv_work pool
219
  // for a single write() call, until all of the input bytes have
220
  // been consumed.
221
761
  static void Process(uv_work_t* work_req) {
222
761
    ZCtx *ctx = ContainerOf(&ZCtx::work_req_, work_req);
223
224
761
    const Bytef* next_expected_header_byte = nullptr;
225
226
    // If the avail_out is left at 0, then it means that it ran out
227
    // of room.  If there was avail_out left over, then it means
228
    // that all of the input was consumed.
229


761
    switch (ctx->mode_) {
230
      case DEFLATE:
231
      case GZIP:
232
      case DEFLATERAW:
233
489
        ctx->err_ = deflate(&ctx->strm_, ctx->flush_);
234
489
        break;
235
      case UNZIP:
236
25
        if (ctx->strm_.avail_in > 0) {
237
25
          next_expected_header_byte = ctx->strm_.next_in;
238
        }
239
240
25
        switch (ctx->gzip_id_bytes_read_) {
241
          case 0:
242
24
            if (next_expected_header_byte == nullptr) {
243
              break;
244
            }
245
246
24
            if (*next_expected_header_byte == GZIP_HEADER_ID1) {
247
18
              ctx->gzip_id_bytes_read_ = 1;
248
18
              next_expected_header_byte++;
249
250
18
              if (ctx->strm_.avail_in == 1) {
251
                // The only available byte was already read.
252
                break;
253
              }
254
            } else {
255
6
              ctx->mode_ = INFLATE;
256
6
              break;
257
            }
258
259
            // fallthrough
260
          case 1:
261
18
            if (next_expected_header_byte == nullptr) {
262
              break;
263
            }
264
265
18
            if (*next_expected_header_byte == GZIP_HEADER_ID2) {
266
18
              ctx->gzip_id_bytes_read_ = 2;
267
18
              ctx->mode_ = GUNZIP;
268
            } else {
269
              // There is no actual difference between INFLATE and INFLATERAW
270
              // (after initialization).
271
              ctx->mode_ = INFLATE;
272
            }
273
274
            break;
275
          default:
276
            CHECK(0 && "invalid number of gzip magic number bytes read");
277
        }
278
279
        // fallthrough
280
      case INFLATE:
281
      case GUNZIP:
282
      case INFLATERAW:
283
272
        ctx->err_ = inflate(&ctx->strm_, ctx->flush_);
284
285
        // If data was encoded with dictionary
286

272
        if (ctx->err_ == Z_NEED_DICT && ctx->dictionary_ != nullptr) {
287
          // Load it
288
3
          ctx->err_ = inflateSetDictionary(&ctx->strm_,
289
                                           ctx->dictionary_,
290
6
                                           ctx->dictionary_len_);
291
3
          if (ctx->err_ == Z_OK) {
292
            // And try to decode again
293
2
            ctx->err_ = inflate(&ctx->strm_, ctx->flush_);
294
1
          } else if (ctx->err_ == Z_DATA_ERROR) {
295
            // Both inflateSetDictionary() and inflate() return Z_DATA_ERROR.
296
            // Make it possible for After() to tell a bad dictionary from bad
297
            // input.
298
1
            ctx->err_ = Z_NEED_DICT;
299
          }
300
        }
301
302
373
        while (ctx->strm_.avail_in > 0 &&
303
102
               ctx->mode_ == GUNZIP &&
304

355
               ctx->err_ == Z_STREAM_END &&
305
22
               ctx->strm_.next_in[0] != 0x00) {
306
          // Bytes remain in input buffer. Perhaps this is another compressed
307
          // member in the same archive, or just trailing garbage.
308
          // Trailing zero bytes are okay, though, since they are frequently
309
          // used for padding.
310
311
20
          Reset(ctx);
312
20
          ctx->err_ = inflate(&ctx->strm_, ctx->flush_);
313
        }
314
        break;
315
      default:
316
        CHECK(0 && "wtf?");
317
    }
318
319
    // pass any errors back to the main thread to deal with.
320
321
    // now After will emit the output, and
322
    // either schedule another call to Process,
323
    // or shift the queue and call Process.
324
761
  }
325
326
327
761
  static bool CheckError(ZCtx* ctx) {
328
    // Acceptable error states depend on the type of zlib stream.
329

761
    switch (ctx->err_) {
330
    case Z_OK:
331
    case Z_BUF_ERROR:
332

556
      if (ctx->strm_.avail_out != 0 && ctx->flush_ == Z_FINISH) {
333
12
        ZCtx::Error(ctx, "unexpected end of file");
334
12
        return false;
335
      }
336
    case Z_STREAM_END:
337
      // normal statuses, not fatal
338
      break;
339
    case Z_NEED_DICT:
340
2
      if (ctx->dictionary_ == nullptr)
341
1
        ZCtx::Error(ctx, "Missing dictionary");
342
      else
343
1
        ZCtx::Error(ctx, "Bad dictionary");
344
      return false;
345
    default:
346
      // something else.
347
9
      ZCtx::Error(ctx, "Zlib error");
348
9
      return false;
349
    }
350
351
    return true;
352
  }
353
354
355
  // v8 land!
356
705
  static void After(uv_work_t* work_req, int status) {
357
705
    CHECK_EQ(status, 0);
358
359
705
    ZCtx* ctx = ContainerOf(&ZCtx::work_req_, work_req);
360
705
    Environment* env = ctx->env();
361
362
1393
    HandleScope handle_scope(env->isolate());
363
2098
    Context::Scope context_scope(env->context());
364
365
705
    if (!CheckError(ctx))
366
17
      return;
367
368
    Local<Integer> avail_out = Integer::New(env->isolate(),
369
688
                                            ctx->strm_.avail_out);
370
    Local<Integer> avail_in = Integer::New(env->isolate(),
371
688
                                           ctx->strm_.avail_in);
372
373
688
    ctx->write_in_progress_ = false;
374
375
    // call the write() cb
376
2064
    Local<Value> args[2] = { avail_in, avail_out };
377
1376
    ctx->MakeCallback(env->callback_string(), arraysize(args), args);
378
379
688
    ctx->Unref();
380
688
    if (ctx->pending_close_)
381
1
      ctx->Close();
382
  }
383
384
23
  static void Error(ZCtx* ctx, const char* message) {
385
23
    Environment* env = ctx->env();
386
387
    // If you hit this assertion, you forgot to enter the v8::Context first.
388
69
    CHECK_EQ(env->context(), env->isolate()->GetCurrentContext());
389
390
23
    if (ctx->strm_.msg != nullptr) {
391
9
      message = ctx->strm_.msg;
392
    }
393
394
46
    HandleScope scope(env->isolate());
395
    Local<Value> args[2] = {
396
      OneByteString(env->isolate(), message),
397
23
      Number::New(env->isolate(), ctx->err_)
398
92
    };
399
46
    ctx->MakeCallback(env->onerror_string(), arraysize(args), args);
400
401
    // no hope of rescue.
402
23
    if (ctx->write_in_progress_)
403
23
      ctx->Unref();
404
23
    ctx->write_in_progress_ = false;
405
23
    if (ctx->pending_close_)
406
23
      ctx->Close();
407
23
  }
408
409
176
  static void New(const FunctionCallbackInfo<Value>& args) {
410
176
    Environment* env = Environment::GetCurrent(args);
411
412

528
    if (args.Length() < 1 || !args[0]->IsInt32()) {
413
      return env->ThrowTypeError("Bad argument");
414
    }
415
176
    node_zlib_mode mode = static_cast<node_zlib_mode>(args[0]->Int32Value());
416
417
176
    if (mode < DEFLATE || mode > UNZIP) {
418
      return env->ThrowTypeError("Bad argument");
419
    }
420
421
176
    new ZCtx(env, args.This(), mode);
422
  }
423
424
  // just pull the ints out of the args and call the other Init
425
176
  static void Init(const FunctionCallbackInfo<Value>& args) {
426


176
    CHECK((args.Length() == 4 || args.Length() == 5) &&
427
           "init(windowBits, level, memLevel, strategy, [dictionary])");
428
429
    ZCtx* ctx;
430
176
    ASSIGN_OR_RETURN_UNWRAP(&ctx, args.Holder());
431
432
176
    int windowBits = args[0]->Uint32Value();
433
176
    CHECK((windowBits >= 8 && windowBits <= 15) && "invalid windowBits");
434
435
176
    int level = args[1]->Int32Value();
436
176
    CHECK((level >= -1 && level <= 9) && "invalid compression level");
437
438
176
    int memLevel = args[2]->Uint32Value();
439
176
    CHECK((memLevel >= 1 && memLevel <= 9) && "invalid memlevel");
440
441
176
    int strategy = args[3]->Uint32Value();
442
176
    CHECK((strategy == Z_FILTERED ||
443
            strategy == Z_HUFFMAN_ONLY ||
444
            strategy == Z_RLE ||
445
            strategy == Z_FIXED ||
446
            strategy == Z_DEFAULT_STRATEGY) && "invalid strategy");
447
448
176
    char* dictionary = nullptr;
449
176
    size_t dictionary_len = 0;
450

352
    if (args.Length() >= 5 && Buffer::HasInstance(args[4])) {
451
10
      Local<Object> dictionary_ = args[4]->ToObject(args.GetIsolate());
452
453
5
      dictionary_len = Buffer::Length(dictionary_);
454
5
      dictionary = new char[dictionary_len];
455
456
10
      memcpy(dictionary, Buffer::Data(dictionary_), dictionary_len);
457
    }
458
459
    Init(ctx, level, windowBits, memLevel, strategy,
460
176
         dictionary, dictionary_len);
461
176
    SetDictionary(ctx);
462
  }
463
464
1
  static void Params(const FunctionCallbackInfo<Value>& args) {
465
1
    CHECK(args.Length() == 2 && "params(level, strategy)");
466
    ZCtx* ctx;
467
1
    ASSIGN_OR_RETURN_UNWRAP(&ctx, args.Holder());
468
2
    Params(ctx, args[0]->Int32Value(), args[1]->Int32Value());
469
  }
470
471
1
  static void Reset(const FunctionCallbackInfo<Value> &args) {
472
    ZCtx* ctx;
473
1
    ASSIGN_OR_RETURN_UNWRAP(&ctx, args.Holder());
474
1
    Reset(ctx);
475
1
    SetDictionary(ctx);
476
  }
477
478
176
  static void Init(ZCtx *ctx, int level, int windowBits, int memLevel,
479
                   int strategy, char* dictionary, size_t dictionary_len) {
480
176
    ctx->level_ = level;
481
176
    ctx->windowBits_ = windowBits;
482
176
    ctx->memLevel_ = memLevel;
483
176
    ctx->strategy_ = strategy;
484
485
176
    ctx->strm_.zalloc = Z_NULL;
486
176
    ctx->strm_.zfree = Z_NULL;
487
176
    ctx->strm_.opaque = Z_NULL;
488
489
176
    ctx->flush_ = Z_NO_FLUSH;
490
491
176
    ctx->err_ = Z_OK;
492
493
176
    if (ctx->mode_ == GZIP || ctx->mode_ == GUNZIP) {
494
81
      ctx->windowBits_ += 16;
495
    }
496
497
176
    if (ctx->mode_ == UNZIP) {
498
24
      ctx->windowBits_ += 32;
499
    }
500
501
176
    if (ctx->mode_ == DEFLATERAW || ctx->mode_ == INFLATERAW) {
502

25
      ctx->windowBits_ *= -1;
503
    }
504
505
    switch (ctx->mode_) {
506
      case DEFLATE:
507
      case GZIP:
508
      case DEFLATERAW:
509
74
        ctx->err_ = deflateInit2(&ctx->strm_,
510
                                 ctx->level_,
511
                                 Z_DEFLATED,
512
                                 ctx->windowBits_,
513
                                 ctx->memLevel_,
514
74
                                 ctx->strategy_);
515
        ctx->env()->isolate()
516
74
            ->AdjustAmountOfExternalAllocatedMemory(kDeflateContextSize);
517
        break;
518
      case INFLATE:
519
      case GUNZIP:
520
      case INFLATERAW:
521
      case UNZIP:
522
102
        ctx->err_ = inflateInit2(&ctx->strm_, ctx->windowBits_);
523
        ctx->env()->isolate()
524
102
            ->AdjustAmountOfExternalAllocatedMemory(kInflateContextSize);
525
        break;
526
      default:
527
        CHECK(0 && "wtf?");
528
    }
529
530
176
    if (ctx->err_ != Z_OK) {
531
      ZCtx::Error(ctx, "Init error");
532
    }
533
534
535
176
    ctx->dictionary_ = reinterpret_cast<Bytef *>(dictionary);
536
176
    ctx->dictionary_len_ = dictionary_len;
537
538
176
    ctx->write_in_progress_ = false;
539
176
    ctx->init_done_ = true;
540
176
  }
541
542
177
  static void SetDictionary(ZCtx* ctx) {
543
177
    if (ctx->dictionary_ == nullptr)
544
      return;
545
546
6
    ctx->err_ = Z_OK;
547
548
6
    switch (ctx->mode_) {
549
      case DEFLATE:
550
      case DEFLATERAW:
551
3
        ctx->err_ = deflateSetDictionary(&ctx->strm_,
552
                                         ctx->dictionary_,
553
6
                                         ctx->dictionary_len_);
554
3
        break;
555
      default:
556
        break;
557
    }
558
559
6
    if (ctx->err_ != Z_OK) {
560
      ZCtx::Error(ctx, "Failed to set dictionary");
561
    }
562
  }
563
564
1
  static void Params(ZCtx* ctx, int level, int strategy) {
565
1
    ctx->err_ = Z_OK;
566
567
1
    switch (ctx->mode_) {
568
      case DEFLATE:
569
      case DEFLATERAW:
570
1
        ctx->err_ = deflateParams(&ctx->strm_, level, strategy);
571
1
        break;
572
      default:
573
        break;
574
    }
575
576
1
    if (ctx->err_ != Z_OK && ctx->err_ != Z_BUF_ERROR) {
577
      ZCtx::Error(ctx, "Failed to set parameters");
578
    }
579
1
  }
580
581
21
  static void Reset(ZCtx* ctx) {
582
21
    ctx->err_ = Z_OK;
583
584

21
    switch (ctx->mode_) {
585
      case DEFLATE:
586
      case DEFLATERAW:
587
      case GZIP:
588
1
        ctx->err_ = deflateReset(&ctx->strm_);
589
1
        break;
590
      case INFLATE:
591
      case INFLATERAW:
592
      case GUNZIP:
593
20
        ctx->err_ = inflateReset(&ctx->strm_);
594
20
        break;
595
      default:
596
        break;
597
    }
598
599
21
    if (ctx->err_ != Z_OK) {
600
      ZCtx::Error(ctx, "Failed to reset stream");
601
    }
602
21
  }
603
604
  size_t self_size() const override { return sizeof(*this); }
605
606
 private:
607
  void Ref() {
608

761
    if (++refs_ == 1) {
609
203
      ClearWeak();
610
    }
611
  }
612
613
761
  void Unref() {
614
761
    CHECK_GT(refs_, 0);
615
761
    if (--refs_ == 0) {
616
203
      MakeWeak<ZCtx>(this);
617
    }
618
761
  }
619
620
  static const int kDeflateContextSize = 16384;  // approximate
621
  static const int kInflateContextSize = 10240;  // approximate
622
623
  Bytef* dictionary_;
624
  size_t dictionary_len_;
625
  int err_;
626
  int flush_;
627
  bool init_done_;
628
  int level_;
629
  int memLevel_;
630
  node_zlib_mode mode_;
631
  int strategy_;
632
  z_stream strm_;
633
  int windowBits_;
634
  uv_work_t work_req_;
635
  bool write_in_progress_;
636
  bool pending_close_;
637
  unsigned int refs_;
638
  unsigned int gzip_id_bytes_read_;
639
};
640
641
642
30
void InitZlib(Local<Object> target,
643
              Local<Value> unused,
644
              Local<Context> context,
645
              void* priv) {
646
30
  Environment* env = Environment::GetCurrent(context);
647
60
  Local<FunctionTemplate> z = env->NewFunctionTemplate(ZCtx::New);
648
649
60
  z->InstanceTemplate()->SetInternalFieldCount(1);
650
651
30
  env->SetProtoMethod(z, "write", ZCtx::Write<true>);
652
30
  env->SetProtoMethod(z, "writeSync", ZCtx::Write<false>);
653
30
  env->SetProtoMethod(z, "init", ZCtx::Init);
654
30
  env->SetProtoMethod(z, "close", ZCtx::Close);
655
30
  env->SetProtoMethod(z, "params", ZCtx::Params);
656
30
  env->SetProtoMethod(z, "reset", ZCtx::Reset);
657
658
30
  z->SetClassName(FIXED_ONE_BYTE_STRING(env->isolate(), "Zlib"));
659
90
  target->Set(FIXED_ONE_BYTE_STRING(env->isolate(), "Zlib"), z->GetFunction());
660
661
120
  target->Set(FIXED_ONE_BYTE_STRING(env->isolate(), "ZLIB_VERSION"),
662
30
              FIXED_ONE_BYTE_STRING(env->isolate(), ZLIB_VERSION));
663
30
}
664
665
}  // namespace node
666
667
1631
NODE_MODULE_CONTEXT_AWARE_BUILTIN(zlib, node::InitZlib)