'use strict'; const zlib = require('zlib'); // tag COMPRESS DEFLATE module.exports = { state: ['Authenticated', 'Selected'], schema: [{ name: 'mechanism', type: 'string' }], handler(command, callback) { let mechanism = (command.attributes[0] && command.attributes[0].value || '').toString().toUpperCase().trim(); if (!mechanism) { return callback(null, { response: 'BAD' }); } if (mechanism !== 'DEFLATE') { return callback(null, { response: 'BAD', code: 'CANNOT', message: 'Unsupported compression mechanism' }); } setImmediate(() => { this.compression = true; this._deflate = zlib.createDeflateRaw({ windowBits: 15 }); this._inflate = zlib.createInflateRaw(); this._deflate.once('error', err => { this._server.logger.debug('[%s] Deflate error %s', this.id, err.message); this.close(); }); this._inflate.once('error', err => { this._server.logger.debug('[%s] Inflate error %s', this.id, err.message); this.close(); }); this.writeStream.unpipe(this._socket); this._deflate.pipe(this._socket); let readNext = () => { let chunk; while ((chunk = this.writeStream.read()) !== null) { if (this._deflate && this._deflate.write(chunk) === false) { return this._deflate.once('drain', readNext); } } // flush data to socket if (this._deflate) { this._deflate.flush(); } }; this.writeStream.on('readable', readNext); this._socket.unpipe(this._parser); this._socket.pipe(this._inflate).pipe(this._parser); }); callback(null, { response: 'OK', message: 'DEFLATE active' }); } };