2
0
mirror of https://github.com/tenrok/axios.git synced 2026-06-11 18:02:32 +03:00

Fixed bug #4727 : toFormData Blob issue on node>v17; (#4728)

* Fixed bug #4727;
Added node 18.x to the CI;
Added hotfix for `ERR_OSSL_EVP_UNSUPPORTED` issue with karma running on node >=17.x;
Added `cross-env` to allow running build and test scripts on Windows platforms;

* Added conditional setting of `--openssl-legacy-provider` option for node versions >=17.x;

* Refactored ssl-hotfix & test script;

* Fixed and refactored default max body length test due to ECONNRESET failure;

* Added test for converting the data uri to a Blob;
Fixed bug with parsing mime type for Blob;

Co-authored-by: Jay <jasonsaayman@gmail.com>
This commit is contained in:
Dmitriy Mozgovoy
2022-05-20 17:31:26 +03:00
committed by GitHub
parent de973f00f3
commit 467025bdb7
8 changed files with 114 additions and 35 deletions
+1 -1
View File
@@ -12,7 +12,7 @@ jobs:
strategy:
matrix:
node-version: [12.x, 14.x, 16.x]
node-version: [12.x, 14.x, 16.x, 18.x]
steps:
- uses: actions/checkout@v2
+22
View File
@@ -0,0 +1,22 @@
const {spawn} = require('child_process');
const args = process.argv.slice(2);
console.log(`Running ${args.join(' ')} on ${process.version}\n`);
const match = /v(\d+)/.exec(process.version);
const isHotfixNeeded = match && match[1] > 16;
isHotfixNeeded && console.warn('Setting --openssl-legacy-provider as ssl hotfix');
const test = spawn('cross-env',
isHotfixNeeded ? ['NODE_OPTIONS=--openssl-legacy-provider', ...args] : args, {
shell: true,
stdio: 'inherit'
}
);
test.on('exit', function (code) {
process.exit(code)
})
+1 -1
View File
@@ -23,7 +23,7 @@ module.exports = function fromDataURI(uri, asBlob, options) {
}
if (protocol === 'data') {
uri = uri.slice(protocol.length);
uri = protocol.length ? uri.slice(protocol.length + 1) : uri;
var match = DATA_URL_PATTERN.exec(uri);
+25 -14
View File
@@ -1,6 +1,7 @@
'use strict';
var utils = require('../utils');
var AxiosError = require('../core/AxiosError');
var envFormData = require('../env/classes/FormData');
function isVisitable(thing) {
@@ -20,20 +21,6 @@ function renderKey(path, key, dots) {
}).join(dots ? '.' : '');
}
function convertValue(value) {
if (value === null) return '';
if (utils.isDate(value)) {
return value.toISOString();
}
if (utils.isArrayBuffer(value) || utils.isTypedArray(value)) {
return typeof Blob === 'function' ? new Blob([value]) : Buffer.from(value);
}
return value;
}
function isFlatArray(arr) {
return utils.isArray(arr) && !arr.some(isVisitable);
}
@@ -42,6 +29,10 @@ var predicates = utils.toFlatObject(utils, {}, null, function filter(prop) {
return /^is[A-Z]/.test(prop);
});
function isSpecCompliant(thing) {
return thing && utils.isFunction(thing.append) && thing[Symbol.toStringTag] === 'FormData' && thing[Symbol.iterator];
}
/**
* Convert a data object to FormData
* @param {Object} obj
@@ -73,11 +64,31 @@ function toFormData(obj, formData, options) {
var visitor = options.visitor || defaultVisitor;
var dots = options.dots;
var indexes = options.indexes;
var _Blob = options.Blob || typeof Blob !== 'undefined' && Blob;
var useBlob = _Blob && isSpecCompliant(formData);
if (!utils.isFunction(visitor)) {
throw new TypeError('visitor must be a function');
}
function convertValue(value) {
if (value === null) return '';
if (utils.isDate(value)) {
return value.toISOString();
}
if (!useBlob && utils.isBlob(value)) {
throw new AxiosError('Blob is not supported. Use a Buffer instead.');
}
if (utils.isArrayBuffer(value) || utils.isTypedArray(value)) {
return useBlob && typeof Blob === 'function' ? new Blob([value]) : Buffer.from(value);
}
return value;
}
/**
*
* @param {*} value
+28
View File
@@ -22,6 +22,7 @@
"abortcontroller-polyfill": "^1.7.3",
"body-parser": "^1.20.0",
"coveralls": "^3.1.1",
"cross-env": "^7.0.3",
"dtslint": "^4.2.1",
"es6-promise": "^4.2.8",
"express": "^4.18.1",
@@ -3815,6 +3816,24 @@
"sha.js": "^2.4.8"
}
},
"node_modules/cross-env": {
"version": "7.0.3",
"resolved": "https://registry.npmjs.org/cross-env/-/cross-env-7.0.3.tgz",
"integrity": "sha512-+/HKd6EgcQCJGh2PSjZuUitQBQynKor4wrFbRg4DtAgS1aWO+gU52xpH7M9ScGgXSYmAVS9bIJ8EzuaGw0oNAw==",
"dev": true,
"dependencies": {
"cross-spawn": "^7.0.1"
},
"bin": {
"cross-env": "src/bin/cross-env.js",
"cross-env-shell": "src/bin/cross-env-shell.js"
},
"engines": {
"node": ">=10.14",
"npm": ">=6",
"yarn": ">=1"
}
},
"node_modules/cross-spawn": {
"version": "7.0.3",
"resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz",
@@ -20215,6 +20234,15 @@
"sha.js": "^2.4.8"
}
},
"cross-env": {
"version": "7.0.3",
"resolved": "https://registry.npmjs.org/cross-env/-/cross-env-7.0.3.tgz",
"integrity": "sha512-+/HKd6EgcQCJGh2PSjZuUitQBQynKor4wrFbRg4DtAgS1aWO+gU52xpH7M9ScGgXSYmAVS9bIJ8EzuaGw0oNAw==",
"dev": true,
"requires": {
"cross-spawn": "^7.0.1"
}
},
"cross-spawn": {
"version": "7.0.3",
"resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz",
+3 -2
View File
@@ -5,10 +5,10 @@
"main": "index.js",
"types": "index.d.ts",
"scripts": {
"test": "grunt test && dtslint",
"test": "node bin/ssl_hotfix.js grunt test && node bin/ssl_hotfix.js dtslint",
"start": "node ./sandbox/server.js",
"preversion": "grunt version && npm test",
"build": "NODE_ENV=production grunt build",
"build": "cross-env NODE_ENV=production grunt build",
"examples": "node ./examples/server.js",
"coveralls": "cat coverage/lcov.info | ./node_modules/coveralls/bin/coveralls.js",
"fix": "eslint --fix lib/**/*.js"
@@ -39,6 +39,7 @@
"abortcontroller-polyfill": "^1.7.3",
"body-parser": "^1.20.0",
"coveralls": "^3.1.1",
"cross-env": "^7.0.3",
"dtslint": "^4.2.1",
"es6-promise": "^4.2.8",
"express": "^4.18.1",
+33 -16
View File
@@ -15,6 +15,9 @@ var formidable = require('formidable');
var express = require('express');
var multer = require('multer');
var bodyParser = require('body-parser');
const isBlobSupported = typeof Blob !== 'undefined';
var noop = ()=> {};
describe('supports http with nodejs', function () {
@@ -572,27 +575,23 @@ describe('supports http with nodejs', function () {
var data = Array(2 * followRedirectsMaxBodyDefaults).join('ж');
server = http.createServer(function (req, res) {
res.setHeader('Content-Type', 'text/html; charset=UTF-8');
res.end();
}).listen(4444, function () {
var success = false, failure = false, error;
// consume the req stream
req.on('data', noop);
// and wait for the end before responding, otherwise an ECONNRESET error will be thrown
req.on('end', ()=> {
res.end('OK');
});
}).listen(4444, function (err) {
if (err) {
return done(err);
}
// send using the default -1 (unlimited axios maxBodyLength)
axios.post('http://localhost:4444/', {
data: data
}).then(function (res) {
success = true;
}).catch(function (err) {
error = err;
failure = true;
});
setTimeout(function () {
assert.equal(success, true, 'request should have succeeded');
assert.equal(failure, false, 'request should not fail');
assert.equal(error, undefined, 'There should not be any error');
assert.equal(res.data, 'OK', 'should handle response');
done();
}, 100);
}).catch(done);
});
});
@@ -1485,6 +1484,24 @@ describe('supports http with nodejs', function () {
}).catch(done);
});
it('should support requesting data URL as a Blob (if supported by the environment)', function (done) {
if (!isBlobSupported) {
this.skip();
return;
}
const buffer = Buffer.from('123');
const dataURI = 'data:application/octet-stream;base64,' + buffer.toString('base64');
axios.get(dataURI, {responseType: 'blob'}).then(async ({data})=> {
assert.strictEqual(data.type, 'application/octet-stream');
assert.deepStrictEqual(await data.text(), '123');
done();
}).catch(done);
});
it('should support requesting data URL as a String (text)', function (done) {
const buffer = Buffer.from('123', 'utf-8');
+1 -1
View File
@@ -7,6 +7,6 @@ describe('helpers::fromDataURI', function () {
const dataURI = 'data:application/octet-stream;base64,' + buffer.toString('base64');
assert.deepStrictEqual(fromDataURI(dataURI), buffer);
assert.deepStrictEqual(fromDataURI(dataURI, false), buffer);
});
});