mirror of
https://github.com/tenrok/axios.git
synced 2026-06-20 20:00:40 +03:00
fix: fixed Brotli decompression; (#5353)
test: added decompression tests; fix: added legacy `x-gzip` & `x-compress` encoding types;
This commit is contained in:
@@ -23,6 +23,11 @@ import EventEmitter from 'events';
|
|||||||
const zlibOptions = {
|
const zlibOptions = {
|
||||||
flush: zlib.constants.Z_SYNC_FLUSH,
|
flush: zlib.constants.Z_SYNC_FLUSH,
|
||||||
finishFlush: zlib.constants.Z_SYNC_FLUSH
|
finishFlush: zlib.constants.Z_SYNC_FLUSH
|
||||||
|
};
|
||||||
|
|
||||||
|
const brotliOptions = {
|
||||||
|
flush: zlib.constants.BROTLI_OPERATION_FLUSH,
|
||||||
|
finishFlush: zlib.constants.BROTLI_OPERATION_FLUSH
|
||||||
}
|
}
|
||||||
|
|
||||||
const isBrotliSupported = utils.isFunction(zlib.createBrotliDecompress);
|
const isBrotliSupported = utils.isFunction(zlib.createBrotliDecompress);
|
||||||
@@ -417,7 +422,9 @@ export default isHttpAdapterSupported && function httpAdapter(config) {
|
|||||||
switch (res.headers['content-encoding']) {
|
switch (res.headers['content-encoding']) {
|
||||||
/*eslint default-case:0*/
|
/*eslint default-case:0*/
|
||||||
case 'gzip':
|
case 'gzip':
|
||||||
|
case 'x-gzip':
|
||||||
case 'compress':
|
case 'compress':
|
||||||
|
case 'x-compress':
|
||||||
case 'deflate':
|
case 'deflate':
|
||||||
// add the unzipper to the body stream processing pipeline
|
// add the unzipper to the body stream processing pipeline
|
||||||
streams.push(zlib.createUnzip(zlibOptions));
|
streams.push(zlib.createUnzip(zlibOptions));
|
||||||
@@ -427,7 +434,7 @@ export default isHttpAdapterSupported && function httpAdapter(config) {
|
|||||||
break;
|
break;
|
||||||
case 'br':
|
case 'br':
|
||||||
if (isBrotliSupported) {
|
if (isBrotliSupported) {
|
||||||
streams.push(zlib.createBrotliDecompress(zlibOptions));
|
streams.push(zlib.createBrotliDecompress(brotliOptions));
|
||||||
delete res.headers['content-encoding'];
|
delete res.headers['content-encoding'];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -43,6 +43,7 @@ const isStandardBrowserEnv = (() => {
|
|||||||
const isStandardBrowserWebWorkerEnv = (() => {
|
const isStandardBrowserWebWorkerEnv = (() => {
|
||||||
return (
|
return (
|
||||||
typeof WorkerGlobalScope !== 'undefined' &&
|
typeof WorkerGlobalScope !== 'undefined' &&
|
||||||
|
// eslint-disable-next-line no-undef
|
||||||
self instanceof WorkerGlobalScope &&
|
self instanceof WorkerGlobalScope &&
|
||||||
typeof self.importScripts === 'function'
|
typeof self.importScripts === 'function'
|
||||||
);
|
);
|
||||||
|
|||||||
+76
-30
@@ -34,6 +34,8 @@ function setTimeoutAsync(ms) {
|
|||||||
const pipelineAsync = util.promisify(stream.pipeline);
|
const pipelineAsync = util.promisify(stream.pipeline);
|
||||||
const finishedAsync = util.promisify(stream.finished);
|
const finishedAsync = util.promisify(stream.finished);
|
||||||
const gzip = util.promisify(zlib.gzip);
|
const gzip = util.promisify(zlib.gzip);
|
||||||
|
const deflate = util.promisify(zlib.deflate);
|
||||||
|
const brotliCompress = util.promisify(zlib.brotliCompress);
|
||||||
|
|
||||||
function toleranceRange(positive, negative) {
|
function toleranceRange(positive, negative) {
|
||||||
const p = (1 + 1 / positive);
|
const p = (1 + 1 / positive);
|
||||||
@@ -432,7 +434,7 @@ describe('supports http with nodejs', function () {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('compression', () => {
|
describe('compression', async () => {
|
||||||
it('should support transparent gunzip', function (done) {
|
it('should support transparent gunzip', function (done) {
|
||||||
var data = {
|
var data = {
|
||||||
firstName: 'Fred',
|
firstName: 'Fred',
|
||||||
@@ -455,17 +457,17 @@ describe('supports http with nodejs', function () {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should support gunzip error handling', async () => {
|
it('should support gunzip error handling', async () => {
|
||||||
server = await startHTTPServer((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');
|
||||||
});
|
});
|
||||||
|
|
||||||
await assert.rejects(async ()=> {
|
await assert.rejects(async () => {
|
||||||
await axios.get(LOCAL_SERVER_URL);
|
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';
|
||||||
@@ -488,32 +490,76 @@ describe('supports http with nodejs', function () {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should properly handle empty responses without Z_BUF_ERROR throwing', async () => {
|
describe('algorithms', ()=> {
|
||||||
this.timeout(10000);
|
const responseBody ='str';
|
||||||
|
|
||||||
server = await startHTTPServer((req, res) => {
|
for (const [type, zipped] of Object.entries({
|
||||||
res.setHeader('Content-Encoding', 'gzip');
|
gzip: gzip(responseBody),
|
||||||
res.end();
|
compress: gzip(responseBody),
|
||||||
});
|
deflate: deflate(responseBody),
|
||||||
|
br: brotliCompress(responseBody)
|
||||||
|
})) {
|
||||||
|
describe(`${type} decompression`, async () => {
|
||||||
|
it(`should support decompression`, async () => {
|
||||||
|
server = await startHTTPServer(async (req, res) => {
|
||||||
|
res.setHeader('Content-Encoding', type);
|
||||||
|
res.end(await zipped);
|
||||||
|
});
|
||||||
|
|
||||||
await axios.get(LOCAL_SERVER_URL);
|
const {data} = await axios.get(LOCAL_SERVER_URL);
|
||||||
});
|
|
||||||
|
|
||||||
it('should not fail if response content-length header is missing', async () => {
|
assert.strictEqual(data, responseBody);
|
||||||
this.timeout(10000);
|
});
|
||||||
|
|
||||||
const str = 'zipped';
|
it(`should not fail if response content-length header is missing (${type})`, async () => {
|
||||||
const zipped = await gzip(str);
|
server = await startHTTPServer(async (req, res) => {
|
||||||
|
res.setHeader('Content-Encoding', type);
|
||||||
|
res.removeHeader('Content-Length');
|
||||||
|
res.end(await zipped);
|
||||||
|
});
|
||||||
|
|
||||||
server = await startHTTPServer((req, res) => {
|
const {data} = await axios.get(LOCAL_SERVER_URL);
|
||||||
res.setHeader('Content-Encoding', 'gzip');
|
|
||||||
res.removeHeader('Content-Length');
|
|
||||||
res.end(zipped);
|
|
||||||
});
|
|
||||||
|
|
||||||
const {data} = await axios.get(LOCAL_SERVER_URL);
|
assert.strictEqual(data, responseBody);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should not fail with chunked responses (without Content-Length header)', async () => {
|
||||||
|
server = await startHTTPServer(async (req, res) => {
|
||||||
|
res.setHeader('Content-Encoding', type);
|
||||||
|
res.setHeader('Transfer-Encoding', 'chunked');
|
||||||
|
res.removeHeader('Content-Length');
|
||||||
|
res.write(await zipped);
|
||||||
|
res.end();
|
||||||
|
});
|
||||||
|
|
||||||
|
const {data} = await axios.get(LOCAL_SERVER_URL);
|
||||||
|
|
||||||
|
assert.strictEqual(data, responseBody);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should not fail with an empty response without content-length header (Z_BUF_ERROR)', async () => {
|
||||||
|
server = await startHTTPServer((req, res) => {
|
||||||
|
res.setHeader('Content-Encoding', type);
|
||||||
|
res.removeHeader('Content-Length');
|
||||||
|
res.end();
|
||||||
|
});
|
||||||
|
|
||||||
|
const {data} = await axios.get(LOCAL_SERVER_URL);
|
||||||
|
|
||||||
|
assert.strictEqual(data, '');
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should not fail with an empty response with content-length header (Z_BUF_ERROR)', async () => {
|
||||||
|
server = await startHTTPServer((req, res) => {
|
||||||
|
res.setHeader('Content-Encoding', type);
|
||||||
|
res.end();
|
||||||
|
});
|
||||||
|
|
||||||
|
await axios.get(LOCAL_SERVER_URL);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
assert.strictEqual(data, str);
|
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user