const zlib = require('zlib'); const concatStream = require('concat-stream'); const BufferHelper = require('bufferhelper'); const { debugLogger } = require('../../utils/logger'); /** * Modify the response * @param res {Object} The http response * @param contentEncoding {String} The http header content-encoding: gzip/deflate * @param callback {Function} Custom modified logic */ const modifyResponse = (res, contentEncoding, callback) => { debugLogger.info('modifyResponse'); debugLogger.info(res.statusCode); debugLogger.info(contentEncoding); let unzip, zip; // Now only deal with the gzip/deflate/undefined content-encoding. switch (contentEncoding) { case 'gzip': unzip = zlib.Gunzip(); zip = zlib.Gzip(); break; case 'deflate': unzip = zlib.Inflate(); zip = zlib.Deflate(); break; } // The cache response method can be called after the modification. const _write = res.write; const _end = res.end; if (unzip) { unzip.on('error', e => { debugLogger.info('Unzip error: ', e); _end.call(res); }); handleCompressed(res, _write, _end, unzip, zip, callback); } else if (!contentEncoding) { handleUncompressed(res, _write, _end, callback); } else { debugLogger.info('Not supported content-encoding: ' + contentEncoding); } }; /** * Handle compressed buffer body */ const handleCompressed = (res, _write, _end, unzip, zip, callback) => { debugLogger.info('handleCompressed'); // The rewrite response method is replaced by unzip stream. res.write = data => { unzip.write(data); }; res.end = () => { unzip.end(); }; // Concat the unzip stream. const concatWrite = concatStream(data => { let body = data.toString(); // Custom modified logic if (typeof callback === 'function') { body = callback(body); } body = Buffer.from(body); res.removeHeader('content-length'); // Call the response method and recover the content-encoding. zip.on('data', chunk => { _write.call(res, chunk); }); zip.on('end', () => { _end.call(res); }); zip.write(body); zip.end(); }); unzip.pipe(concatWrite); }; /** * Handle Uncompressed buffer body */ const handleUncompressed = (res, _write, _end, callback) => { debugLogger.info('handleUncompressed'); const buffer = new BufferHelper(); // Rewrite response method and get the content. res.write = data => { buffer.concat(data); }; res.end = () => { let body = buffer.toBuffer().toString(); // Custom modified logic if (typeof callback === 'function') { body = callback(body); } body = Buffer.from(body); res.removeHeader('content-length'); // Call the response method _write.call(res, body); _end.call(res); }; }; module.exports = modifyResponse;