Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

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

Merged
merged 2 commits into from Nov 22, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
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