2
0
mirror of https://github.com/tenrok/axios.git synced 2026-06-20 20:00:40 +03:00

Fixed Z_BUF_ERROR when content-encoding is set but the response body is empty; (#5250)

Fixed download progress capturing for compressed responses;

Co-authored-by: Jay <jasonsaayman@gmail.com>
This commit is contained in:
Dmitriy Mozgovoy
2022-11-22 20:49:26 +02:00
committed by GitHub
parent b7ee49f637
commit a3d901777b
2 changed files with 76 additions and 59 deletions
+18 -18
View File
@@ -373,6 +373,23 @@ export default function httpAdapter(config) {
const streams = [res]; 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 // uncompress the response body transparently if required
let responseStream = res; let responseStream = res;
@@ -383,7 +400,7 @@ export default function httpAdapter(config) {
if (config.decompress !== false) { if (config.decompress !== false) {
// if no content, but headers still say that it is encoded, // if no content, but headers still say that it is encoded,
// remove the header not confuse downstream operations // 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']; delete res.headers['content-encoding'];
} }
@@ -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]; responseStream = streams.length > 1 ? stream.pipeline(streams, utils.noop) : streams[0];
const offListeners = stream.finished(responseStream, () => { const offListeners = stream.finished(responseStream, () => {
+58 -41
View File
@@ -47,9 +47,14 @@ var noop = ()=> {};
const LOCAL_SERVER_URL = 'http://localhost:4444'; 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) => { return new Promise((resolve, reject) => {
http.createServer(async function (req, res) { http.createServer(handler || async function (req, res) {
try { try {
req.headers['content-length'] && res.setHeader('content-length', req.headers['content-length']); req.headers['content-length'] && res.setHeader('content-length', req.headers['content-length']);
@@ -426,59 +431,72 @@ describe('supports http with nodejs', function () {
}); });
}); });
it('should support transparent gunzip', function (done) { describe('compression', () => {
var data = { it('should support transparent gunzip', function (done) {
firstName: 'Fred', var data = {
lastName: 'Flintstone', firstName: 'Fred',
emailAddr: 'fred@example.com' 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) { server = http.createServer(function (req, res) {
res.setHeader('Content-Type', 'application/json'); res.setHeader('Content-Type', 'application/json');
res.setHeader('Content-Encoding', 'gzip'); res.setHeader('Content-Encoding', 'gzip');
res.end(zipped); res.end(zipped);
}).listen(4444, function () { }).listen(4444, function () {
axios.get('http://localhost:4444/').then(function (res) { axios.get('http://localhost:4444/').then(function (res) {
assert.deepEqual(res.data, data); assert.deepEqual(res.data, data);
done(); done();
}).catch(done); }).catch(done);
});
}); });
}); });
});
it('should support gunzip error handling', function (done) { it('should support gunzip error handling', async () => {
server = http.createServer(function (req, res) { server = await startHTTPServer((req, res) => {
res.setHeader('Content-Type', 'application/json'); res.setHeader('Content-Type', 'application/json');
res.setHeader('Content-Encoding', 'gzip'); res.setHeader('Content-Encoding', 'gzip');
res.end('invalid response'); 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) { it('should support disabling automatic decompression of response data', function(done) {
var data = 'Test data'; var data = 'Test data';
zlib.gzip(data, function(err, zipped) { zlib.gzip(data, function(err, zipped) {
server = http.createServer(function(req, res) { server = http.createServer(function(req, res) {
res.setHeader('Content-Type', 'text/html;charset=utf-8'); res.setHeader('Content-Type', 'text/html;charset=utf-8');
res.setHeader('Content-Encoding', 'gzip'); res.setHeader('Content-Encoding', 'gzip');
res.end(zipped); res.end(zipped);
}).listen(4444, function() { }).listen(4444, function() {
axios.get('http://localhost:4444/', { axios.get('http://localhost:4444/', {
decompress: false, decompress: false,
responseType: 'arraybuffer' responseType: 'arraybuffer'
}).then(function(res) { }).then(function(res) {
assert.equal(res.data.toString('base64'), zipped.toString('base64')); assert.equal(res.data.toString('base64'), zipped.toString('base64'));
done(); done();
}).catch(done); }).catch(done);
});
}); });
}); });
it('should properly handle empty responses without Z_BUF_ERROR throwing', async () => {
this.timeout(10000);
server = await startHTTPServer((req, res) => {
res.setHeader('Content-Encoding', 'gzip');
res.end();
});
await axios.get(LOCAL_SERVER_URL);
});
}); });
it('should support UTF8', function (done) { it('should support UTF8', function (done) {
@@ -1887,7 +1905,6 @@ describe('supports http with nodejs', function () {
}); });
}); });
describe('request aborting', function() { describe('request aborting', function() {
it('should be able to abort the response stream', async function () { it('should be able to abort the response stream', async function () {
server = await startHTTPServer({ server = await startHTTPServer({