Skip to content

Commit

Permalink
Fixed Z_BUF_ERROR when content-encoding is set but the response body …
Browse files Browse the repository at this point in the history
…is empty; (#5250)

Fixed download progress capturing for compressed responses;

Co-authored-by: Jay <jasonsaayman@gmail.com>
  • Loading branch information
DigitalBrainJS and jasonsaayman committed Nov 22, 2022
1 parent b7ee49f commit a3d9017
Show file tree
Hide file tree
Showing 2 changed files with 76 additions and 59 deletions.
36 changes: 18 additions & 18 deletions lib/adapters/http.js
Expand Up @@ -373,6 +373,23 @@ export default function httpAdapter(config) {

const streams = [res];

const responseLength = +res.headers['content-length'];

if (onDownloadProgress) {
const transformStream = new AxiosTransformStream({
length: utils.toFiniteNumber(responseLength),
maxRate: utils.toFiniteNumber(maxDownloadRate)
});

onDownloadProgress && transformStream.on('progress', progress => {
onDownloadProgress(Object.assign(progress, {
download: true
}));
});

streams.push(transformStream);
}

// uncompress the response body transparently if required
let responseStream = res;

Expand All @@ -383,7 +400,7 @@ export default function httpAdapter(config) {
if (config.decompress !== false) {
// if no content, but headers still say that it is encoded,
// remove the header not confuse downstream operations
if (data && data.length === 0 && res.headers['content-encoding']) {
if ((!responseLength || res.statusCode === 204) && res.headers['content-encoding']) {
delete res.headers['content-encoding'];
}

Expand All @@ -406,23 +423,6 @@ export default function httpAdapter(config) {
}
}

if (onDownloadProgress) {
const responseLength = +res.headers['content-length'];

const transformStream = new AxiosTransformStream({
length: utils.toFiniteNumber(responseLength),
maxRate: utils.toFiniteNumber(maxDownloadRate)
});

onDownloadProgress && transformStream.on('progress', progress => {
onDownloadProgress(Object.assign(progress, {
download: true
}));
});

streams.push(transformStream);
}

responseStream = streams.length > 1 ? stream.pipeline(streams, utils.noop) : streams[0];

const offListeners = stream.finished(responseStream, () => {
Expand Down
99 changes: 58 additions & 41 deletions test/unit/adapters/http.js
Expand Up @@ -47,9 +47,14 @@ var noop = ()=> {};

const LOCAL_SERVER_URL = 'http://localhost:4444';

function startHTTPServer({useBuffering= false, rate = undefined, port = 4444} = {}) {
function startHTTPServer(options) {

const {handler, useBuffering = false, rate = undefined, port = 4444} = typeof options === 'function' ? {
handler: options
} : options || {};

return new Promise((resolve, reject) => {
http.createServer(async function (req, res) {
http.createServer(handler || async function (req, res) {
try {
req.headers['content-length'] && res.setHeader('content-length', req.headers['content-length']);

Expand Down Expand Up @@ -426,58 +431,71 @@ describe('supports http with nodejs', function () {
});
});

it('should support transparent gunzip', function (done) {
var data = {
firstName: 'Fred',
lastName: 'Flintstone',
emailAddr: 'fred@example.com'
};
describe('compression', () => {
it('should support transparent gunzip', function (done) {
var data = {
firstName: 'Fred',
lastName: 'Flintstone',
emailAddr: 'fred@example.com'
};

zlib.gzip(JSON.stringify(data), function (err, zipped) {
zlib.gzip(JSON.stringify(data), function (err, zipped) {

server = http.createServer(function (req, res) {
res.setHeader('Content-Type', 'application/json');
res.setHeader('Content-Encoding', 'gzip');
res.end(zipped);
}).listen(4444, function () {
axios.get('http://localhost:4444/').then(function (res) {
assert.deepEqual(res.data, data);
done();
}).catch(done);
server = http.createServer(function (req, res) {
res.setHeader('Content-Type', 'application/json');
res.setHeader('Content-Encoding', 'gzip');
res.end(zipped);
}).listen(4444, function () {
axios.get('http://localhost:4444/').then(function (res) {
assert.deepEqual(res.data, data);
done();
}).catch(done);
});
});
});
});

it('should support gunzip error handling', function (done) {
server = http.createServer(function (req, res) {
it('should support gunzip error handling', async () => {
server = await startHTTPServer((req, res) => {
res.setHeader('Content-Type', 'application/json');
res.setHeader('Content-Encoding', 'gzip');
res.end('invalid response');
}).listen(4444, function () {
axios.get('http://localhost:4444/').catch(function (error) {
done();
}).catch(done);
});

await assert.rejects(async ()=> {
await axios.get(LOCAL_SERVER_URL);
})
});

it('should support disabling automatic decompression of response data', function(done) {
var data = 'Test data';
it('should support disabling automatic decompression of response data', function(done) {
var data = 'Test data';

zlib.gzip(data, function(err, zipped) {
server = http.createServer(function(req, res) {
res.setHeader('Content-Type', 'text/html;charset=utf-8');
res.setHeader('Content-Encoding', 'gzip');
res.end(zipped);
}).listen(4444, function() {
axios.get('http://localhost:4444/', {
decompress: false,
responseType: 'arraybuffer'

}).then(function(res) {
assert.equal(res.data.toString('base64'), zipped.toString('base64'));
done();
}).catch(done);
});
});
});

it('should properly handle empty responses without Z_BUF_ERROR throwing', async () => {
this.timeout(10000);

zlib.gzip(data, function(err, zipped) {
server = http.createServer(function(req, res) {
res.setHeader('Content-Type', 'text/html;charset=utf-8');
server = await startHTTPServer((req, res) => {
res.setHeader('Content-Encoding', 'gzip');
res.end(zipped);
}).listen(4444, function() {
axios.get('http://localhost:4444/', {
decompress: false,
responseType: 'arraybuffer'

}).then(function(res) {
assert.equal(res.data.toString('base64'), zipped.toString('base64'));
done();
}).catch(done);
res.end();
});

await axios.get(LOCAL_SERVER_URL);
});
});

Expand Down Expand Up @@ -1887,7 +1905,6 @@ describe('supports http with nodejs', function () {
});
});


describe('request aborting', function() {
it('should be able to abort the response stream', async function () {
server = await startHTTPServer({
Expand Down

0 comments on commit a3d9017

Please sign in to comment.