Skip to content

Commit

Permalink
Fixed decompression for responses without Content-Length header (#5306
Browse files Browse the repository at this point in the history
)

* Fixed decompression for responses without `content-length` header;

* Add Brotli encoding to the `Accept-Encoding` header only if it is supported.

* `content-length` header transformation moved up;

Co-authored-by: Jay <jasonsaayman@gmail.com>
  • Loading branch information
DigitalBrainJS and jasonsaayman committed Dec 1, 2022
1 parent 786b113 commit 9041c7d
Show file tree
Hide file tree
Showing 2 changed files with 34 additions and 9 deletions.
24 changes: 16 additions & 8 deletions lib/adapters/http.js
Expand Up @@ -20,6 +20,11 @@ import AxiosHeaders from '../core/AxiosHeaders.js';
import AxiosTransformStream from '../helpers/AxiosTransformStream.js';
import EventEmitter from 'events';

const zlibOptions = {
flush: zlib.constants.Z_SYNC_FLUSH,
finishFlush: zlib.constants.Z_SYNC_FLUSH
}

const isBrotliSupported = utils.isFunction(zlib.createBrotliDecompress);

const {http: httpFollow, https: httpsFollow} = followRedirects;
Expand Down Expand Up @@ -262,7 +267,7 @@ export default isHttpAdapterSupported && function httpAdapter(config) {
}
}

const contentLength = +headers.getContentLength();
const contentLength = utils.toFiniteNumber(headers.getContentLength());

if (utils.isArray(maxRate)) {
maxUploadRate = maxRate[0];
Expand All @@ -277,7 +282,7 @@ export default isHttpAdapterSupported && function httpAdapter(config) {
}

data = stream.pipeline([data, new AxiosTransformStream({
length: utils.toFiniteNumber(contentLength),
length: contentLength,
maxRate: utils.toFiniteNumber(maxUploadRate)
})], utils.noop);

Expand Down Expand Up @@ -320,7 +325,10 @@ export default isHttpAdapterSupported && function httpAdapter(config) {
return reject(customErr);
}

headers.set('Accept-Encoding', 'gzip, deflate, br', false);
headers.set(
'Accept-Encoding',
'gzip, compress, deflate' + (isBrotliSupported ? ', br' : ''), false
);

const options = {
path,
Expand Down Expand Up @@ -392,17 +400,17 @@ export default isHttpAdapterSupported && function httpAdapter(config) {
streams.push(transformStream);
}

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

// return the last request in case of redirects
const lastRequest = res.req || req;

// if decompress disabled we should not decompress
if (config.decompress !== false) {
if (config.decompress !== false && res.headers['content-encoding']) {
// if no content, but headers still say that it is encoded,
// remove the header not confuse downstream operations
if ((!responseLength || res.statusCode === 204) && res.headers['content-encoding']) {
if (method === 'HEAD' || res.statusCode === 204) {
delete res.headers['content-encoding'];
}

Expand All @@ -412,14 +420,14 @@ export default isHttpAdapterSupported && function httpAdapter(config) {
case 'compress':
case 'deflate':
// add the unzipper to the body stream processing pipeline
streams.push(zlib.createUnzip());
streams.push(zlib.createUnzip(zlibOptions));

// remove the content-encoding in order to not confuse downstream operations
delete res.headers['content-encoding'];
break;
case 'br':
if (isBrotliSupported) {
streams.push(zlib.createBrotliDecompress());
streams.push(zlib.createBrotliDecompress(zlibOptions));
delete res.headers['content-encoding'];
}
}
Expand Down
19 changes: 18 additions & 1 deletion test/unit/adapters/http.js
Expand Up @@ -33,6 +33,7 @@ function setTimeoutAsync(ms) {

const pipelineAsync = util.promisify(stream.pipeline);
const finishedAsync = util.promisify(stream.finished);
const gzip = util.promisify(zlib.gzip);

function toleranceRange(positive, negative) {
const p = (1 + 1 / positive);
Expand Down Expand Up @@ -497,6 +498,23 @@ describe('supports http with nodejs', function () {

await axios.get(LOCAL_SERVER_URL);
});

it('should not fail if response content-length header is missing', async () => {
this.timeout(10000);

const str = 'zipped';
const zipped = await gzip(str);

server = await startHTTPServer((req, res) => {
res.setHeader('Content-Encoding', 'gzip');
res.removeHeader('Content-Length');
res.end(zipped);
});

const {data} = await axios.get(LOCAL_SERVER_URL);

assert.strictEqual(data, str);
});
});

it('should support UTF8', function (done) {
Expand Down Expand Up @@ -1411,7 +1429,6 @@ describe('supports http with nodejs', function () {

it('should omit a user-agent if one is explicitly disclaimed', function (done) {
server = http.createServer(function (req, res) {
console.log(req.headers);
assert.equal("user-agent" in req.headers, false);
assert.equal("User-Agent" in req.headers, false);
res.end();
Expand Down

0 comments on commit 9041c7d

Please sign in to comment.