|
|
'use strict'; |
|
|
const {Transform, PassThrough} = require('stream'); |
|
|
const zlib = require('zlib'); |
|
|
const mimicResponse = require('mimic-response'); |
|
|
|
|
|
module.exports = response => { |
|
|
const contentEncoding = (response.headers['content-encoding'] || '').toLowerCase(); |
|
|
|
|
|
if (!['gzip', 'deflate', 'br'].includes(contentEncoding)) { |
|
|
return response; |
|
|
} |
|
|
|
|
|
|
|
|
const isBrotli = contentEncoding === 'br'; |
|
|
if (isBrotli && typeof zlib.createBrotliDecompress !== 'function') { |
|
|
response.destroy(new Error('Brotli is not supported on Node.js < 12')); |
|
|
return response; |
|
|
} |
|
|
|
|
|
let isEmpty = true; |
|
|
|
|
|
const checker = new Transform({ |
|
|
transform(data, _encoding, callback) { |
|
|
isEmpty = false; |
|
|
|
|
|
callback(null, data); |
|
|
}, |
|
|
|
|
|
flush(callback) { |
|
|
callback(); |
|
|
} |
|
|
}); |
|
|
|
|
|
const finalStream = new PassThrough({ |
|
|
autoDestroy: false, |
|
|
destroy(error, callback) { |
|
|
response.destroy(); |
|
|
|
|
|
callback(error); |
|
|
} |
|
|
}); |
|
|
|
|
|
const decompressStream = isBrotli ? zlib.createBrotliDecompress() : zlib.createUnzip(); |
|
|
|
|
|
decompressStream.once('error', error => { |
|
|
if (isEmpty && !response.readable) { |
|
|
finalStream.end(); |
|
|
return; |
|
|
} |
|
|
|
|
|
finalStream.destroy(error); |
|
|
}); |
|
|
|
|
|
mimicResponse(response, finalStream); |
|
|
response.pipe(checker).pipe(decompressStream).pipe(finalStream); |
|
|
|
|
|
return finalStream; |
|
|
}; |
|
|
|