123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255 |
- 'use strict';
- const { kMaxLength } = require('buffer');
- const {
- createInflate,
- constants: {
- DEFLATE,
- INFLATE,
- Z_DEFAULT_CHUNK,
- Z_DEFAULT_COMPRESSION,
- Z_DEFAULT_MEMLEVEL,
- Z_DEFAULT_STRATEGY,
- Z_DEFAULT_WINDOWBITS,
- Z_PARTIAL_FLUSH,
- }
- } = require('zlib');
- const ZlibHandle = createInflate()._handle.constructor;
- function processCallback() {
- throw new Error('Should not get here');
- }
- function zlibOnError(message, errno, code) {
- const self = this._owner;
- // There is no way to cleanly recover.
- // Continuing only obscures problems.
- const error = new Error(message);
- error.errno = errno;
- error.code = code;
- self._err = error;
- }
- function _close(engine) {
- // Caller may invoke .close after a zlib error (which will null _handle).
- if (!engine._handle)
- return;
- engine._handle.close();
- engine._handle = null;
- }
- class Zlib {
- constructor(mode) {
- const windowBits = Z_DEFAULT_WINDOWBITS;
- const level = Z_DEFAULT_COMPRESSION;
- const memLevel = Z_DEFAULT_MEMLEVEL;
- const strategy = Z_DEFAULT_STRATEGY;
- const dictionary = undefined;
- this._err = undefined;
- this._writeState = new Uint32Array(2);
- this._chunkSize = Z_DEFAULT_CHUNK;
- this._maxOutputLength = kMaxLength;
- this._outBuffer = Buffer.allocUnsafe(this._chunkSize);
- this._outOffset = 0;
- this._handle = new ZlibHandle(mode);
- this._handle._owner = this;
- this._handle.onerror = zlibOnError;
- this._handle.init(windowBits,
- level,
- memLevel,
- strategy,
- this._writeState,
- processCallback,
- dictionary);
- }
- writeSync(chunk, retChunks) {
- const handle = this._handle;
- if (!handle)
- throw new Error('Invalid Zlib instance');
- let availInBefore = chunk.length;
- let availOutBefore = this._chunkSize - this._outOffset;
- let inOff = 0;
- let availOutAfter;
- let availInAfter;
- let buffers;
- let nread = 0;
- const state = this._writeState;
- let buffer = this._outBuffer;
- let offset = this._outOffset;
- const chunkSize = this._chunkSize;
- while (true) {
- handle.writeSync(Z_PARTIAL_FLUSH,
- chunk, // in
- inOff, // in_off
- availInBefore, // in_len
- buffer, // out
- offset, // out_off
- availOutBefore); // out_len
- if (this._err)
- throw this._err;
- availOutAfter = state[0];
- availInAfter = state[1];
- const inDelta = availInBefore - availInAfter;
- const have = availOutBefore - availOutAfter;
- if (have > 0) {
- const out = (offset === 0 && have === buffer.length
- ? buffer
- : buffer.slice(offset, offset + have));
- offset += have;
- if (!buffers)
- buffers = out;
- else if (buffers.push === undefined)
- buffers = [buffers, out];
- else
- buffers.push(out);
- nread += out.byteLength;
- if (nread > this._maxOutputLength) {
- _close(this);
- throw new Error(
- `Output length exceeded maximum of ${this._maxOutputLength}`
- );
- }
- } else if (have !== 0) {
- throw new Error('have should not go down');
- }
- // Exhausted the output buffer, or used all the input create a new one.
- if (availOutAfter === 0 || offset >= chunkSize) {
- availOutBefore = chunkSize;
- offset = 0;
- buffer = Buffer.allocUnsafe(chunkSize);
- }
- if (availOutAfter === 0) {
- // Not actually done. Need to reprocess.
- // Also, update the availInBefore to the availInAfter value,
- // so that if we have to hit it a third (fourth, etc.) time,
- // it'll have the correct byte counts.
- inOff += inDelta;
- availInBefore = availInAfter;
- } else {
- break;
- }
- }
- this._outBuffer = buffer;
- this._outOffset = offset;
- if (nread === 0)
- buffers = Buffer.alloc(0);
- if (retChunks) {
- buffers.totalLen = nread;
- return buffers;
- }
- if (buffers.push === undefined)
- return buffers;
- const output = Buffer.allocUnsafe(nread);
- for (let i = 0, p = 0; i < buffers.length; ++i) {
- const buf = buffers[i];
- output.set(buf, p);
- p += buf.length;
- }
- return output;
- }
- }
- class ZlibPacketWriter {
- constructor(protocol) {
- this.allocStart = 0;
- this.allocStartKEX = 0;
- this._protocol = protocol;
- this._zlib = new Zlib(DEFLATE);
- }
- cleanup() {
- if (this._zlib)
- _close(this._zlib);
- }
- alloc(payloadSize, force) {
- return Buffer.allocUnsafe(payloadSize);
- }
- finalize(payload, force) {
- if (this._protocol._kexinit === undefined || force) {
- const output = this._zlib.writeSync(payload, true);
- const packet = this._protocol._cipher.allocPacket(output.totalLen);
- if (output.push === undefined) {
- packet.set(output, 5);
- } else {
- for (let i = 0, p = 5; i < output.length; ++i) {
- const chunk = output[i];
- packet.set(chunk, p);
- p += chunk.length;
- }
- }
- return packet;
- }
- return payload;
- }
- }
- class PacketWriter {
- constructor(protocol) {
- this.allocStart = 5;
- this.allocStartKEX = 5;
- this._protocol = protocol;
- }
- cleanup() {}
- alloc(payloadSize, force) {
- if (this._protocol._kexinit === undefined || force)
- return this._protocol._cipher.allocPacket(payloadSize);
- return Buffer.allocUnsafe(payloadSize);
- }
- finalize(packet, force) {
- return packet;
- }
- }
- class ZlibPacketReader {
- constructor() {
- this._zlib = new Zlib(INFLATE);
- }
- cleanup() {
- if (this._zlib)
- _close(this._zlib);
- }
- read(data) {
- return this._zlib.writeSync(data, false);
- }
- }
- class PacketReader {
- cleanup() {}
- read(data) {
- return data;
- }
- }
- module.exports = {
- PacketReader,
- PacketWriter,
- ZlibPacketReader,
- ZlibPacketWriter,
- };
|