From 96d336f527619f21da012fe1f117eeb53e5a2120 Mon Sep 17 00:00:00 2001 From: Dmitriy Mozgovoy Date: Thu, 2 Feb 2023 00:55:05 +0200 Subject: [PATCH] fix(formdata): add hotfix to use the asynchronous API to compute the content-length header value; (#5521) --- lib/adapters/http.js | 17 ++++++++++++----- lib/core/AxiosHeaders.js | 2 +- package.json | 2 +- test/unit/adapters/axios.png | Bin 0 -> 1716 bytes test/unit/adapters/http.js | 12 ++++++++++++ 5 files changed, 26 insertions(+), 7 deletions(-) create mode 100644 test/unit/adapters/axios.png diff --git a/lib/adapters/http.js b/lib/adapters/http.js index 17e3a1de9d..d03db3a622 100755 --- a/lib/adapters/http.js +++ b/lib/adapters/http.js @@ -7,6 +7,7 @@ import buildURL from './../helpers/buildURL.js'; import {getProxyForUrl} from 'proxy-from-env'; import http from 'http'; import https from 'https'; +import util from 'util'; import followRedirects from 'follow-redirects'; import zlib from 'zlib'; import {VERSION} from '../env/data.js'; @@ -117,7 +118,8 @@ const isHttpAdapterSupported = typeof process !== 'undefined' && utils.kindOf(pr /*eslint consistent-return:0*/ export default isHttpAdapterSupported && function httpAdapter(config) { - return new Promise(function dispatchHttpRequest(resolvePromise, rejectPromise) { + /*eslint no-async-promise-executor:0*/ + return new Promise(async function dispatchHttpRequest(resolvePromise, rejectPromise) { let data = config.data; const responseType = config.responseType; const responseEncoding = config.responseEncoding; @@ -208,7 +210,7 @@ export default isHttpAdapterSupported && function httpAdapter(config) { convertedData = convertedData.toString(responseEncoding); if (!responseEncoding || responseEncoding === 'utf8') { - data = utils.stripBOM(convertedData); + convertedData = utils.stripBOM(convertedData); } } else if (responseType === 'stream') { convertedData = stream.Readable.from(convertedData); @@ -258,9 +260,14 @@ export default isHttpAdapterSupported && function httpAdapter(config) { // support for https://www.npmjs.com/package/form-data api } else if (utils.isFormData(data) && utils.isFunction(data.getHeaders)) { headers.set(data.getHeaders()); - if (utils.isFunction(data.getLengthSync)) { // check if the undocumented API exists - const knownLength = data.getLengthSync(); - !utils.isUndefined(knownLength) && headers.setContentLength(knownLength, false); + + if (!headers.hasContentLength()) { + try { + const knownLength = await util.promisify(data.getLength).call(data); + headers.setContentLength(knownLength); + /*eslint no-empty:0*/ + } catch (e) { + } } } else if (utils.isBlob(data)) { data.size && headers.setContentType(data.type || 'application/octet-stream'); diff --git a/lib/core/AxiosHeaders.js b/lib/core/AxiosHeaders.js index 858a3d078c..1cf84b9458 100644 --- a/lib/core/AxiosHeaders.js +++ b/lib/core/AxiosHeaders.js @@ -141,7 +141,7 @@ class AxiosHeaders { if (header) { const key = utils.findKey(this, header); - return !!(key && (!matcher || matchHeaderValue(this, this[key], key, matcher))); + return !!(key && this[key] !== undefined && (!matcher || matchHeaderValue(this, this[key], key, matcher))); } return false; diff --git a/package.json b/package.json index 0fe12e82d5..6de48442fd 100644 --- a/package.json +++ b/package.json @@ -204,4 +204,4 @@ "@commitlint/config-conventional" ] } -} \ No newline at end of file +} diff --git a/test/unit/adapters/axios.png b/test/unit/adapters/axios.png new file mode 100644 index 0000000000000000000000000000000000000000..8511175953c2ef062ebb6d073df7715a4037a7f6 GIT binary patch literal 1716 zcmah~>08o?8pUPYQWI2~NG&GZmrRXter~w0hzld6xs*aST8Ilw)5I0G%$o~2gq9Aj zh?bO^x!gOZb*EH79nCR!YYlwPQbNjGUQ{3k;beZYCD5Qq^xPzKS25=`5G3sj z6lRG>X&{h_pPwf>oEE)$yH{v^N;4-h&!vH(W&D5?aKOq;aYQKq#$lK`t0NFlU#sG4 zF8v`6f4oOv&czT*YHGM!!9=O9WWs)}peQSg`?^Cu--(hr(QFEVgOvquL|Kx*i|{Fu zVAt(*@d?+xvrvlL)t|w;yKm=Oq)#vR?ACnaX2TL=5jn|d@WqsC+p^#nzmVHe507o( zAb*~2gbvuPVkq<-G1szZXF2tvKg91b3!82GO5oTihF#A^n{Ipv&~)g}M$ zI=N2opw}&oJ;1mzRW6I<&CW2bi!iTpor4LIfu`V>f-C`>3~?N)Fj9^Bge=1F7?`+J zS?#wLH;Z%4sI{4T7Ut{H;j6Z9#g@Idrt=pY={NA1S(YJ?*zYDhvNt4?cLBhf*+tKE zRNVR@sMjcX3oZ}57O<^JrQE>nDatjwl7iysfq@;jR(Zn_M0%2fa+}KP*o*=4;rU8E zwT6?%UNrM>J$i%Fa(hl9ez~%YGbWL!~VHXG$hwYt#d- zF;#~1L%S#0W=Lk{_1f<6eKu5Rny`rhYlK%WAZ(2(n8p-06eb_HWU2`VF^1i(>HoUY z*=CJN7(C-5PzdAI=6bZmcZ_a(5&+_Q1M0!O)n2_sim+aZx~aUO#Dp-Xz?a6$0p?iq`v_>j?oI2lm-2_9TM&&C`k( ztP2t2o?%#Yc7nCmk|gbOtH(rQXC$@!W!dX9<~z3BfWd{8^QvD?InI;2wI}0{I#oQZE^Tg%ai2EibVx}3FI~> zF}a=w%+C?AnG*NewY${=_#^BU}zQt*t zQSR$-LIXvI!o3MXl)t#w|Gh1q_pT8uN9VtaURnXCn zPciy;3V>I^gDpsz+Ww5iScNF}g$WlkuX_CI#{m&UhnaoJTGUFUxl*+O&JUmB2~7sj*MJ(lr* D`%5b= literal 0 HcmV?d00001 diff --git a/test/unit/adapters/http.js b/test/unit/adapters/http.js index 23faa3b92d..5b500f957e 100644 --- a/test/unit/adapters/http.js +++ b/test/unit/adapters/http.js @@ -1576,6 +1576,10 @@ describe('supports http with nodejs', function () { it('should allow passing FormData', function (done) { var form = new FormDataLegacy(); var file1 = Buffer.from('foo', 'utf8'); + const image = path.resolve(__dirname, './axios.png'); + const fileStream = fs.createReadStream(image); + + const stat = fs.statSync(image); form.append('foo', "bar"); form.append('file1', file1, { @@ -1584,9 +1588,13 @@ describe('supports http with nodejs', function () { contentType: 'image/jpeg' }); + form.append('fileStream', fileStream); + server = http.createServer(function (req, res) { var receivedForm = new formidable.IncomingForm(); + assert.ok(req.rawHeaders.find(header => header.toLowerCase() === 'content-length')); + receivedForm.parse(req, function (err, fields, files) { if (err) { return done(err); @@ -1609,6 +1617,10 @@ describe('supports http with nodejs', function () { assert.strictEqual(res.data.files.file1.originalFilename, 'temp/bar.jpg'); assert.strictEqual(res.data.files.file1.size, 3); + assert.strictEqual(res.data.files.fileStream.mimetype, 'image/png'); + assert.strictEqual(res.data.files.fileStream.originalFilename, 'axios.png'); + assert.strictEqual(res.data.files.fileStream.size, stat.size); + done(); }).catch(done); });