From 5c2ca96a9761e1c66c70562e0039ba4fb8029453 Mon Sep 17 00:00:00 2001 From: MrBBot Date: Sun, 11 Sep 2022 16:01:55 +0100 Subject: [PATCH] fix(fetch): allow third-party `FormData`/`Blob` bodies `webidl.converters.XMLHttpRequestBodyInit` rejected third-party `FormData`/`Blob`s, meaning they were passed through `webidl.converters.DOMString`. This meant `Request`/`Response`s constructed with third-party `FormData`/`Blob` bodies ended up with a plain-text `[object FormData]`/`[object Blob]` body. --- lib/fetch/response.js | 6 +++--- test/fetch/request.js | 24 ++++++++++++++++++++++++ test/fetch/response.js | 18 ++++++++++++++++++ 3 files changed, 45 insertions(+), 3 deletions(-) diff --git a/lib/fetch/response.js b/lib/fetch/response.js index a6a3c70d3f3..198beb9c226 100644 --- a/lib/fetch/response.js +++ b/lib/fetch/response.js @@ -519,7 +519,7 @@ webidl.converters.XMLHttpRequestBodyInit = function (V) { } if (isBlobLike(V)) { - return webidl.converters.Blob(V) + return webidl.converters.Blob(V, { strict: false }) } if ( @@ -530,8 +530,8 @@ webidl.converters.XMLHttpRequestBodyInit = function (V) { return webidl.converters.BufferSource(V) } - if (V instanceof FormData) { - return webidl.converters.FormData(V) + if (util.isFormDataLike(V)) { + return webidl.converters.FormData(V, { strict: false }) } if (V instanceof URLSearchParams) { diff --git a/test/fetch/request.js b/test/fetch/request.js index a76b19ed30f..de91df91479 100644 --- a/test/fetch/request.js +++ b/test/fetch/request.js @@ -9,6 +9,10 @@ const { fetch } = require('../../') const { kState } = require('../../lib/fetch/symbols.js') +const { + Blob: ThirdPartyBlob, + FormData: ThirdPartyFormData +} = require('formdata-node') const hasSignalReason = !!~process.version.localeCompare('v16.14.0', undefined, { numeric: true }) test('arg validation', async (t) => { @@ -435,3 +439,23 @@ test('RequestInit.signal option', async (t) => { signal: false }), TypeError) }) + +test('constructing Request with third party Blob body', async (t) => { + const blob = new ThirdPartyBlob(['text']) + const req = new Request('http://asd', { + method: 'POST', + body: blob + }) + t.equal(await req.text(), 'text') +}) +test('constructing Request with third party FormData body', async (t) => { + const form = new ThirdPartyFormData() + form.set('key', 'value') + const req = new Request('http://asd', { + method: 'POST', + body: form + }) + const contentType = req.headers.get('content-type').split('=') + t.equal(contentType[0], 'multipart/form-data; boundary') + t.ok((await req.text()).startsWith(`--${contentType[1]}`)) +}) diff --git a/test/fetch/response.js b/test/fetch/response.js index 9252c875e49..c031d6d90d1 100644 --- a/test/fetch/response.js +++ b/test/fetch/response.js @@ -5,6 +5,10 @@ const { Response } = require('../../') const { ReadableStream } = require('stream/web') +const { + Blob: ThirdPartyBlob, + FormData: ThirdPartyFormData +} = require('formdata-node') test('arg validation', async (t) => { // constructor @@ -230,3 +234,17 @@ test('constructing a Response with a ReadableStream body', async (t) => { t.end() }) + +test('constructing Response with third party Blob body', async (t) => { + const blob = new ThirdPartyBlob(['text']) + const res = new Response(blob) + t.equal(await res.text(), 'text') +}) +test('constructing Response with third party FormData body', async (t) => { + const form = new ThirdPartyFormData() + form.set('key', 'value') + const res = new Response(form) + const contentType = res.headers.get('content-type').split('=') + t.equal(contentType[0], 'multipart/form-data; boundary') + t.ok((await res.text()).startsWith(`--${contentType[1]}`)) +})