Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Appearance settings

Commit e534dcd

Browse filesBrowse files
addaleaxtargos
authored andcommitted
zlib: split JS code as prep for non-zlib-backed streams
Split the `Zlib` class into `ZlibBase` and `Zlib` classes, to facilitate introduction of similar streams with minor implementation differences. Backport-PR-URL: #25228 PR-URL: #24939 Reviewed-By: Ben Noordhuis <info@bnoordhuis.nl>
1 parent d718625 commit e534dcd
Copy full SHA for e534dcd

File tree

Expand file treeCollapse file tree

1 file changed

+128
-111
lines changed
Open diff view settings
Filter options
Expand file treeCollapse file tree

1 file changed

+128
-111
lines changed
Open diff view settings
Collapse file

‎lib/zlib.js‎

Copy file name to clipboardExpand all lines: lib/zlib.js
+128-111Lines changed: 128 additions & 111 deletions
Original file line numberDiff line numberDiff line change
@@ -206,21 +206,10 @@ function checkRangesOrGetDefault(number, name, lower, upper, def) {
206206
return number;
207207
}
208208

209-
// the Zlib class they all inherit from
210-
// This thing manages the queue of requests, and returns
211-
// true or false if there is anything in the queue when
212-
// you call the .write() method.
213-
function Zlib(opts, mode) {
209+
// The base class for all Zlib-style streams.
210+
function ZlibBase(opts, mode, handle, { flush, finishFlush, fullFlush }) {
214211
var chunkSize = Z_DEFAULT_CHUNK;
215-
var flush = Z_NO_FLUSH;
216-
var finishFlush = Z_FINISH;
217-
var windowBits = Z_DEFAULT_WINDOWBITS;
218-
var level = Z_DEFAULT_COMPRESSION;
219-
var memLevel = Z_DEFAULT_MEMLEVEL;
220-
var strategy = Z_DEFAULT_STRATEGY;
221-
var dictionary;
222-
223-
// The Zlib class is not exported to user land, the mode should only be
212+
// The ZlibBase class is not exported to user land, the mode should only be
224213
// passed in by us.
225214
assert(typeof mode === 'number');
226215
assert(mode >= DEFLATE && mode <= UNZIP);
@@ -236,50 +225,11 @@ function Zlib(opts, mode) {
236225

237226
flush = checkRangesOrGetDefault(
238227
opts.flush, 'options.flush',
239-
Z_NO_FLUSH, Z_BLOCK, Z_NO_FLUSH);
228+
Z_NO_FLUSH, Z_BLOCK, flush);
240229

241230
finishFlush = checkRangesOrGetDefault(
242231
opts.finishFlush, 'options.finishFlush',
243-
Z_NO_FLUSH, Z_BLOCK, Z_FINISH);
244-
245-
// windowBits is special. On the compression side, 0 is an invalid value.
246-
// But on the decompression side, a value of 0 for windowBits tells zlib
247-
// to use the window size in the zlib header of the compressed stream.
248-
if ((opts.windowBits == null || opts.windowBits === 0) &&
249-
(mode === INFLATE ||
250-
mode === GUNZIP ||
251-
mode === UNZIP)) {
252-
windowBits = 0;
253-
} else {
254-
windowBits = checkRangesOrGetDefault(
255-
opts.windowBits, 'options.windowBits',
256-
Z_MIN_WINDOWBITS, Z_MAX_WINDOWBITS, Z_DEFAULT_WINDOWBITS);
257-
}
258-
259-
level = checkRangesOrGetDefault(
260-
opts.level, 'options.level',
261-
Z_MIN_LEVEL, Z_MAX_LEVEL, Z_DEFAULT_COMPRESSION);
262-
263-
memLevel = checkRangesOrGetDefault(
264-
opts.memLevel, 'options.memLevel',
265-
Z_MIN_MEMLEVEL, Z_MAX_MEMLEVEL, Z_DEFAULT_MEMLEVEL);
266-
267-
strategy = checkRangesOrGetDefault(
268-
opts.strategy, 'options.strategy',
269-
Z_DEFAULT_STRATEGY, Z_FIXED, Z_DEFAULT_STRATEGY);
270-
271-
dictionary = opts.dictionary;
272-
if (dictionary !== undefined && !isArrayBufferView(dictionary)) {
273-
if (isAnyArrayBuffer(dictionary)) {
274-
dictionary = Buffer.from(dictionary);
275-
} else {
276-
throw new ERR_INVALID_ARG_TYPE(
277-
'options.dictionary',
278-
['Buffer', 'TypedArray', 'DataView', 'ArrayBuffer'],
279-
dictionary
280-
);
281-
}
282-
}
232+
Z_NO_FLUSH, Z_BLOCK, finishFlush);
283233

284234
if (opts.encoding || opts.objectMode || opts.writableObjectMode) {
285235
opts = _extend({}, opts);
@@ -288,39 +238,29 @@ function Zlib(opts, mode) {
288238
opts.writableObjectMode = false;
289239
}
290240
}
241+
291242
Transform.call(this, opts);
243+
this._hadError = false;
292244
this.bytesWritten = 0;
293-
this._handle = new binding.Zlib(mode);
245+
this._handle = handle;
246+
handle[owner_symbol] = this;
294247
// Used by processCallback() and zlibOnError()
295-
this._handle[owner_symbol] = this;
296-
this._handle.onerror = zlibOnError;
297-
this._hadError = false;
298-
this._writeState = new Uint32Array(2);
299-
300-
if (!this._handle.init(windowBits,
301-
level,
302-
memLevel,
303-
strategy,
304-
this._writeState,
305-
processCallback,
306-
dictionary)) {
307-
throw new ERR_ZLIB_INITIALIZATION_FAILED();
308-
}
309-
248+
handle.onerror = zlibOnError;
310249
this._outBuffer = Buffer.allocUnsafe(chunkSize);
311250
this._outOffset = 0;
312-
this._level = level;
313-
this._strategy = strategy;
251+
314252
this._chunkSize = chunkSize;
315253
this._defaultFlushFlag = flush;
316254
this._finishFlushFlag = finishFlush;
317255
this._nextFlush = -1;
318-
this._info = opts && opts.info;
256+
this._defaultFullFlushFlag = fullFlush;
319257
this.once('end', this.close);
258+
this._info = opts && opts.info;
320259
}
321-
inherits(Zlib, Transform);
322260

323-
Object.defineProperty(Zlib.prototype, '_closed', {
261+
inherits(ZlibBase, Transform);
262+
263+
Object.defineProperty(ZlibBase.prototype, '_closed', {
324264
configurable: true,
325265
enumerable: true,
326266
get() {
@@ -332,7 +272,7 @@ Object.defineProperty(Zlib.prototype, '_closed', {
332272
// perspective, but it is inconsistent with all other streams exposed by Node.js
333273
// that have this concept, where it stands for the number of bytes read
334274
// *from* the stream (that is, net.Socket/tls.Socket & file system streams).
335-
Object.defineProperty(Zlib.prototype, 'bytesRead', {
275+
Object.defineProperty(ZlibBase.prototype, 'bytesRead', {
336276
configurable: true,
337277
enumerable: true,
338278
get: deprecate(function() {
@@ -345,41 +285,15 @@ Object.defineProperty(Zlib.prototype, 'bytesRead', {
345285
'This feature will be removed in the future.', 'DEP0108')
346286
});
347287

348-
// This callback is used by `.params()` to wait until a full flush happened
349-
// before adjusting the parameters. In particular, the call to the native
350-
// `params()` function should not happen while a write is currently in progress
351-
// on the threadpool.
352-
function paramsAfterFlushCallback(level, strategy, callback) {
353-
assert(this._handle, 'zlib binding closed');
354-
this._handle.params(level, strategy);
355-
if (!this._hadError) {
356-
this._level = level;
357-
this._strategy = strategy;
358-
if (callback) callback();
359-
}
360-
}
361-
362-
Zlib.prototype.params = function params(level, strategy, callback) {
363-
checkRangesOrGetDefault(level, 'level', Z_MIN_LEVEL, Z_MAX_LEVEL);
364-
checkRangesOrGetDefault(strategy, 'strategy', Z_DEFAULT_STRATEGY, Z_FIXED);
365-
366-
if (this._level !== level || this._strategy !== strategy) {
367-
this.flush(Z_SYNC_FLUSH,
368-
paramsAfterFlushCallback.bind(this, level, strategy, callback));
369-
} else {
370-
process.nextTick(callback);
371-
}
372-
};
373-
374-
Zlib.prototype.reset = function reset() {
288+
ZlibBase.prototype.reset = function() {
375289
if (!this._handle)
376290
assert(false, 'zlib binding closed');
377291
return this._handle.reset();
378292
};
379293

380294
// This is the _flush function called by the transform class,
381295
// internally, when the last chunk has been written.
382-
Zlib.prototype._flush = function _flush(callback) {
296+
ZlibBase.prototype._flush = function(callback) {
383297
this._transform(Buffer.alloc(0), '', callback);
384298
};
385299

@@ -400,12 +314,12 @@ function maxFlush(a, b) {
400314
}
401315

402316
const flushBuffer = Buffer.alloc(0);
403-
Zlib.prototype.flush = function flush(kind, callback) {
317+
ZlibBase.prototype.flush = function(kind, callback) {
404318
var ws = this._writableState;
405319

406320
if (typeof kind === 'function' || (kind === undefined && !callback)) {
407321
callback = kind;
408-
kind = Z_FULL_FLUSH;
322+
kind = this._defaultFullFlushFlag;
409323
}
410324

411325
if (ws.ended) {
@@ -424,17 +338,17 @@ Zlib.prototype.flush = function flush(kind, callback) {
424338
}
425339
};
426340

427-
Zlib.prototype.close = function close(callback) {
341+
ZlibBase.prototype.close = function(callback) {
428342
_close(this, callback);
429343
this.destroy();
430344
};
431345

432-
Zlib.prototype._destroy = function _destroy(err, callback) {
346+
ZlibBase.prototype._destroy = function(err, callback) {
433347
_close(this);
434348
callback(err);
435349
};
436350

437-
Zlib.prototype._transform = function _transform(chunk, encoding, cb) {
351+
ZlibBase.prototype._transform = function(chunk, encoding, cb) {
438352
var flushFlag = this._defaultFlushFlag;
439353
// We use a 'fake' zero-length chunk to carry information about flushes from
440354
// the public API to the actual stream implementation.
@@ -451,7 +365,7 @@ Zlib.prototype._transform = function _transform(chunk, encoding, cb) {
451365
processChunk(this, chunk, flushFlag, cb);
452366
};
453367

454-
Zlib.prototype._processChunk = function _processChunk(chunk, flushFlag, cb) {
368+
ZlibBase.prototype._processChunk = function(chunk, flushFlag, cb) {
455369
// _processChunk() is left for backwards compatibility
456370
if (typeof cb === 'function')
457371
processChunk(this, chunk, flushFlag, cb);
@@ -641,6 +555,109 @@ function _close(engine, callback) {
641555
engine._handle = null;
642556
}
643557

558+
const zlibDefaultOpts = {
559+
flush: Z_NO_FLUSH,
560+
finishFlush: Z_FINISH,
561+
fullFlush: Z_FULL_FLUSH
562+
};
563+
// Base class for all streams actually backed by zlib and using zlib-specific
564+
// parameters.
565+
function Zlib(opts, mode) {
566+
var windowBits = Z_DEFAULT_WINDOWBITS;
567+
var level = Z_DEFAULT_COMPRESSION;
568+
var memLevel = Z_DEFAULT_MEMLEVEL;
569+
var strategy = Z_DEFAULT_STRATEGY;
570+
var dictionary;
571+
572+
if (opts) {
573+
// windowBits is special. On the compression side, 0 is an invalid value.
574+
// But on the decompression side, a value of 0 for windowBits tells zlib
575+
// to use the window size in the zlib header of the compressed stream.
576+
if ((opts.windowBits == null || opts.windowBits === 0) &&
577+
(mode === INFLATE ||
578+
mode === GUNZIP ||
579+
mode === UNZIP)) {
580+
windowBits = 0;
581+
} else {
582+
windowBits = checkRangesOrGetDefault(
583+
opts.windowBits, 'options.windowBits',
584+
Z_MIN_WINDOWBITS, Z_MAX_WINDOWBITS, Z_DEFAULT_WINDOWBITS);
585+
}
586+
587+
level = checkRangesOrGetDefault(
588+
opts.level, 'options.level',
589+
Z_MIN_LEVEL, Z_MAX_LEVEL, Z_DEFAULT_COMPRESSION);
590+
591+
memLevel = checkRangesOrGetDefault(
592+
opts.memLevel, 'options.memLevel',
593+
Z_MIN_MEMLEVEL, Z_MAX_MEMLEVEL, Z_DEFAULT_MEMLEVEL);
594+
595+
strategy = checkRangesOrGetDefault(
596+
opts.strategy, 'options.strategy',
597+
Z_DEFAULT_STRATEGY, Z_FIXED, Z_DEFAULT_STRATEGY);
598+
599+
dictionary = opts.dictionary;
600+
if (dictionary !== undefined && !isArrayBufferView(dictionary)) {
601+
if (isAnyArrayBuffer(dictionary)) {
602+
dictionary = Buffer.from(dictionary);
603+
} else {
604+
throw new ERR_INVALID_ARG_TYPE(
605+
'options.dictionary',
606+
['Buffer', 'TypedArray', 'DataView', 'ArrayBuffer'],
607+
dictionary
608+
);
609+
}
610+
}
611+
}
612+
613+
const handle = new binding.Zlib(mode);
614+
// Ideally, we could let ZlibBase() set up _writeState. I haven't been able
615+
// to come up with a good solution that doesn't break our internal API,
616+
// and with it all supported npm versions at the time of writing.
617+
this._writeState = new Uint32Array(2);
618+
if (!handle.init(windowBits,
619+
level,
620+
memLevel,
621+
strategy,
622+
this._writeState,
623+
processCallback,
624+
dictionary)) {
625+
throw new ERR_ZLIB_INITIALIZATION_FAILED();
626+
}
627+
628+
ZlibBase.call(this, opts, mode, handle, zlibDefaultOpts);
629+
630+
this._level = level;
631+
this._strategy = strategy;
632+
}
633+
inherits(Zlib, ZlibBase);
634+
635+
// This callback is used by `.params()` to wait until a full flush happened
636+
// before adjusting the parameters. In particular, the call to the native
637+
// `params()` function should not happen while a write is currently in progress
638+
// on the threadpool.
639+
function paramsAfterFlushCallback(level, strategy, callback) {
640+
assert(this._handle, 'zlib binding closed');
641+
this._handle.params(level, strategy);
642+
if (!this._hadError) {
643+
this._level = level;
644+
this._strategy = strategy;
645+
if (callback) callback();
646+
}
647+
}
648+
649+
Zlib.prototype.params = function params(level, strategy, callback) {
650+
checkRangesOrGetDefault(level, 'level', Z_MIN_LEVEL, Z_MAX_LEVEL);
651+
checkRangesOrGetDefault(strategy, 'strategy', Z_DEFAULT_STRATEGY, Z_FIXED);
652+
653+
if (this._level !== level || this._strategy !== strategy) {
654+
this.flush(Z_SYNC_FLUSH,
655+
paramsAfterFlushCallback.bind(this, level, strategy, callback));
656+
} else {
657+
process.nextTick(callback);
658+
}
659+
};
660+
644661
// generic zlib
645662
// minimal 2-byte header
646663
function Deflate(opts) {

0 commit comments

Comments
0 (0)
Morty Proxy This is a proxified and sanitized view of the page, visit original site.