/** * permessage-deflate implementation.
*/ class PerMessageDeflate { /** * Creates a PerMessageDeflate instance. * * @param {Object} [options] Configuration options * @param {(Boolean|Number)} [options.clientMaxWindowBits] Advertise support * for, or request, a custom client window size * @param {Boolean} [options.clientNoContextTakeover=false] Advertise/ * acknowledge disabling of client context takeover * @param {Number} [options.concurrencyLimit=10] The number of concurrent * calls to zlib * @param {(Boolean|Number)} [options.serverMaxWindowBits] Request/confirm the * use of a custom server window size * @param {Boolean} [options.serverNoContextTakeover=false] Request/accept * disabling of server context takeover * @param {Number} [options.threshold=1024] Size (in bytes) below which * messages should not be compressed if context takeover is disabled * @param {Object} [options.zlibDeflateOptions] Options to pass to zlib on * deflate * @param {Object} [options.zlibInflateOptions] Options to pass to zlib on * inflate * @param {Boolean} [isServer=false] Create the instance in either server or * client mode * @param {Number} [maxPayload=0] The maximum allowed message length
*/
constructor(options, isServer, maxPayload) { this._maxPayload = maxPayload | 0; this._options = options || {}; this._threshold = this._options.threshold !== undefined ? this._options.threshold : 1024; this._isServer = !!isServer; this._deflate = null; this._inflate = null;
this.params = null;
if (!zlibLimiter) { const concurrency = this._options.concurrencyLimit !== undefined
? this._options.concurrencyLimit
: 10;
zlibLimiter = new Limiter(concurrency);
}
}
/** * Normalize parameters. * * @param {Array} configurations The extension negotiation offers/reponse * @return {Array} The offers/response with normalized parameters * @private
*/
normalizeParams(configurations) {
configurations.forEach((params) => {
Object.keys(params).forEach((key) => {
let value = params[key];
if (value.length > 1) { thrownew Error(`Parameter "${key}" must have only a single value`);
}
value = value[0];
if (key === 'client_max_window_bits') { if (value !== true) { const num = +value; if (!Number.isInteger(num) || num < 8 || num > 15) { thrownew TypeError(
`Invalid value for parameter "${key}": ${value}`
);
}
value = num;
} elseif (!this._isServer) { thrownew TypeError(
`Invalid value for parameter "${key}": ${value}`
);
}
} elseif (key === 'server_max_window_bits') { const num = +value; if (!Number.isInteger(num) || num < 8 || num > 15) { thrownew TypeError(
`Invalid value for parameter "${key}": ${value}`
);
}
value = num;
} elseif (
key === 'client_no_context_takeover' ||
key === 'server_no_context_takeover'
) { if (value !== true) { thrownew TypeError(
`Invalid value for parameter "${key}": ${value}`
);
}
} else { thrownew Error(`Unknown parameter "${key}"`);
}
params[key] = value;
});
});
return configurations;
}
/** * Decompress data. Concurrency limited. * * @param {Buffer} data Compressed data * @param {Boolean} fin Specifies whether or not this is the last fragment * @param {Function} callback Callback * @public
*/
decompress(data, fin, callback) {
zlibLimiter.add((done) => { this._decompress(data, fin, (err, result) => {
done();
callback(err, result);
});
});
}
/** * Compress data. Concurrency limited. * * @param {(Buffer|String)} data Data to compress * @param {Boolean} fin Specifies whether or not this is the last fragment * @param {Function} callback Callback * @public
*/
compress(data, fin, callback) {
zlibLimiter.add((done) => { this._compress(data, fin, (err, result) => {
done();
callback(err, result);
});
});
}
/** * Decompress data. * * @param {Buffer} data Compressed data * @param {Boolean} fin Specifies whether or not this is the last fragment * @param {Function} callback Callback * @private
*/
_decompress(data, fin, callback) { const endpoint = this._isServer ? 'client' : 'server';
if (fin && this.params[`${endpoint}_no_context_takeover`]) { this._inflate.reset();
}
}
callback(null, data);
});
}
/** * Compress data. * * @param {(Buffer|String)} data Data to compress * @param {Boolean} fin Specifies whether or not this is the last fragment * @param {Function} callback Callback * @private
*/
_compress(data, fin, callback) { const endpoint = this._isServer ? 'server' : 'client';
this._deflate.write(data); this._deflate.flush(zlib.Z_SYNC_FLUSH, () => { if (!this._deflate) { // // The deflate stream was closed while data was being processed. // return;
}
let data = bufferUtil.concat( this._deflate[kBuffers], this._deflate[kTotalLength]
);
if (fin) data = data.slice(0, data.length - 4);
// // Ensure that the callback will not be called again in // `PerMessageDeflate#cleanup()`. // this._deflate[kCallback] = null;
if (fin && this.params[`${endpoint}_no_context_takeover`]) { this._deflate.reset();
}
callback(null, data);
});
}
}
module.exports = PerMessageDeflate;
/** * The listener of the `zlib.DeflateRaw` stream `'data'` event. * * @param {Buffer} chunk A chunk of data * @private
*/ function deflateOnData(chunk) { this[kBuffers].push(chunk); this[kTotalLength] += chunk.length;
}
/** * The listener of the `zlib.InflateRaw` stream `'data'` event. * * @param {Buffer} chunk A chunk of data * @private
*/ function inflateOnData(chunk) { this[kTotalLength] += chunk.length;
/** * The listener of the `zlib.InflateRaw` stream `'error'` event. * * @param {Error} err The emitted error * @private
*/ function inflateOnError(err) { // // There is no need to call `Zlib#close()` as the handle is automatically // closed when an error is emitted. // this[kPerMessageDeflate]._inflate = null;
err[kStatusCode] = 1007; this[kCallback](err);
}
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung ist noch experimentell.