From 55399bf3f51d934f0a25153fbcebb1fd2c3119c5 Mon Sep 17 00:00:00 2001 From: cola119 Date: Tue, 19 Jul 2022 20:22:45 +0900 Subject: [PATCH] fix: x-www-form-urlencoded parser keep the BOM --- lib/fetch/body.js | 13 ++++++++++++- test/fetch/client-fetch.js | 36 ++++++++++++++++++++++++++++++++++++ 2 files changed, 48 insertions(+), 1 deletion(-) diff --git a/lib/fetch/body.js b/lib/fetch/body.js index 2a9f1c83d88..08d22310a38 100644 --- a/lib/fetch/body.js +++ b/lib/fetch/body.js @@ -404,7 +404,18 @@ function bodyMixinMethods (instance) { // 1. Let entries be the result of parsing bytes. let entries try { - entries = new URLSearchParams(await this.text()) + let text = '' + // application/x-www-form-urlencoded parser will keep the BOM. + // https://url.spec.whatwg.org/#concept-urlencoded-parser + const textDecoder = new TextDecoder('utf-8', { ignoreBOM: true }) + for await (const chunk of consumeBody(this[kState].body)) { + if (!isUint8Array(chunk)) { + throw new TypeError('Expected Uint8Array chunk') + } + text += textDecoder.decode(chunk, { stream: true }) + } + text += textDecoder.decode() + entries = new URLSearchParams(text) } catch (err) { // istanbul ignore next: Unclear when new URLSearchParams can fail on a string. // 2. If entries is failure, then throw a TypeError. diff --git a/test/fetch/client-fetch.js b/test/fetch/client-fetch.js index 90d6660dd86..4ec4545d544 100644 --- a/test/fetch/client-fetch.js +++ b/test/fetch/client-fetch.js @@ -202,6 +202,42 @@ test('urlencoded formData', (t) => { }) }) +test('text with BOM', (t) => { + t.plan(1) + + const server = createServer((req, res) => { + res.setHeader('content-type', 'application/x-www-form-urlencoded') + res.end('\uFEFFtest=\uFEFF') + }) + t.teardown(server.close.bind(server)) + + server.listen(0, () => { + fetch(`http://localhost:${server.address().port}`) + .then(res => res.text()) + .then(text => { + t.equal(text, 'test=\uFEFF') + }) + }) +}) + +test('formData with BOM', (t) => { + t.plan(1) + + const server = createServer((req, res) => { + res.setHeader('content-type', 'application/x-www-form-urlencoded') + res.end('\uFEFFtest=\uFEFF') + }) + t.teardown(server.close.bind(server)) + + server.listen(0, () => { + fetch(`http://localhost:${server.address().port}`) + .then(res => res.formData()) + .then(formData => { + t.equal(formData.get('\uFEFFtest'), '\uFEFF') + }) + }) +}) + test('locked blob body', (t) => { t.plan(1)