Skip to content

Commit

Permalink
zlib: fix inheritance of DeflateRaw without class
Browse files Browse the repository at this point in the history
Fixes internal/util createClassWrapper to support inheritance
without using classes. The constructor now needs to be defined
using a Symbol.

Fixes: #13358
  • Loading branch information
mcollina committed Jun 1, 2017
1 parent 9b73062 commit fbfe686
Show file tree
Hide file tree
Showing 4 changed files with 108 additions and 3 deletions.
9 changes: 8 additions & 1 deletion lib/internal/util.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ const { createPromise, promiseResolve, promiseReject } = binding;
const kArrowMessagePrivateSymbolIndex = binding['arrow_message_private_symbol'];
const kDecoratedPrivateSymbolIndex = binding['decorated_private_symbol'];
const noCrypto = !process.versions.openssl;
const constructor = Symbol('constructor');

function isError(e) {
return objectToString(e) === '[object Error]' || e instanceof Error;
Expand Down Expand Up @@ -146,7 +147,12 @@ function cachedResult(fn) {
// B() instanceof B // true
function createClassWrapper(type) {
function fn(...args) {
return Reflect.construct(type, args, new.target || type);
if (this && !new.target && this[constructor]) {
this[constructor](...args);
return this;
} else {
return Reflect.construct(type, args, new.target || type);
}
}
// Mask the wrapper function name and length values
Object.defineProperties(fn, {
Expand Down Expand Up @@ -267,6 +273,7 @@ module.exports = {
normalizeEncoding,
objectToString,
promisify,
constructor,

// Symbol used to customize promisify conversion
customPromisifyArgs: kCustomPromisifyArgsSymbol,
Expand Down
40 changes: 39 additions & 1 deletion lib/zlib.js
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ const kRangeErrorMessage = 'Cannot create final Buffer. It would be larger ' +

const constants = process.binding('constants').zlib;
const createClassWrapper = internalUtil.createClassWrapper;
const constructor = internalUtil.constructor;

// translation table for return codes.
const codes = {
Expand Down Expand Up @@ -175,8 +176,17 @@ class Zlib extends Transform {
opts = opts || {};
super(opts);

this.bytesRead = 0;
this[constructor](opts, mode);
}

[constructor](opts, mode) {
if (!this._readableState) {
// this is being called through util.inherits
opts = opts || {};
Transform.call(this, opts);
}

this.bytesRead = 0;
this._opts = opts;
this._chunkSize = opts.chunkSize || constants.Z_DEFAULT_CHUNK;

Expand Down Expand Up @@ -506,42 +516,70 @@ class Deflate extends Zlib {
constructor(opts) {
super(opts, constants.DEFLATE);
}

[constructor](opts) {
super[constructor](opts, constants.DEFLATE);
}
}

class Inflate extends Zlib {
constructor(opts) {
super(opts, constants.INFLATE);
}

[constructor](opts) {
super[constructor](opts, constants.INFLATE);
}
}

class Gzip extends Zlib {
constructor(opts) {
super(opts, constants.GZIP);
}

[constructor](opts) {
super[constructor](opts, constants.GZIP);
}
}

class Gunzip extends Zlib {
constructor(opts) {
super(opts, constants.GUNZIP);
}

[constructor](opts) {
super[constructor](opts, constants.GUNZIP);
}
}

class DeflateRaw extends Zlib {
constructor(opts) {
super(opts, constants.DEFLATERAW);
}

[constructor](opts) {
super[constructor](opts, constants.DEFLATERAW);
}
}

class InflateRaw extends Zlib {
constructor(opts) {
super(opts, constants.INFLATERAW);
}

[constructor](opts) {
super[constructor](opts, constants.INFLATERAW);
}
}

class Unzip extends Zlib {
constructor(opts) {
super(opts, constants.UNZIP);
}

[constructor](opts) {
super[constructor](opts, constants.UNZIP);
}
}

function createConvenienceMethod(type, sync) {
Expand Down
35 changes: 34 additions & 1 deletion test/parallel/test-internal-util-classwrapper.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,16 @@
require('../common');
const assert = require('assert');
const util = require('internal/util');
const { inherits } = require('util');

const createClassWrapper = util.createClassWrapper;

class A {
constructor(a, b, c) {
constructor() {
this[util.constructor](...arguments);
}

[util.constructor](a, b, c) {
this.a = a;
this.b = b;
this.c = c;
Expand All @@ -17,6 +22,8 @@ class A {

const B = createClassWrapper(A);

B.prototype.func = function() {};

assert.strictEqual(typeof B, 'function');
assert(B(1, 2, 3) instanceof B);
assert(B(1, 2, 3) instanceof A);
Expand All @@ -29,3 +36,29 @@ const b = new B(1, 2, 3);
assert.strictEqual(b.a, 1);
assert.strictEqual(b.b, 2);
assert.strictEqual(b.c, 3);
assert.strictEqual(b.func, B.prototype.func);

function C(a, b, c) {
if (!(this instanceof C)) {
return new C(a, b, c);
}
B.call(this, a, b, c);
}

inherits(C, B);

C.prototype.kaboom = function() {};

const c = new C(4, 2, 3);
assert.strictEqual(c.a, 4);
assert.strictEqual(c.b, 2);
assert.strictEqual(c.c, 3);
assert.strictEqual(c.kaboom, C.prototype.kaboom);
assert.strictEqual(c.func, B.prototype.func);

const c2 = C(4, 2, 3);
assert.strictEqual(c2.a, 4);
assert.strictEqual(c2.b, 2);
assert.strictEqual(c2.c, 3);
assert.strictEqual(c2.kaboom, C.prototype.kaboom);
assert.strictEqual(c2.func, B.prototype.func);
27 changes: 27 additions & 0 deletions test/parallel/test-zlib-deflate-raw-inherits.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
'use strict';

require('../common');
const zlib = require('zlib');
const inherits = require('util').inherits;
const { Readable } = require('stream');

// validates that zlib.DeflateRaw can be inherited
// with util.inherits

function NotInitialized(options) {
zlib.DeflateRaw.call(this, options);
this.prop = true;
}
inherits(NotInitialized, zlib.DeflateRaw);

const dest = new NotInitialized();

const read = new Readable({
read() {
this.push(Buffer.from('a test string'));
this.push(null);
}
});

read.pipe(dest);
dest.resume();

0 comments on commit fbfe686

Please sign in to comment.