From 66124cbf35fa4dbc7ed5d6dbf7b60afb2cd50b0b Mon Sep 17 00:00:00 2001 From: Khafra <42794878+KhafraDev@users.noreply.github.com> Date: Tue, 19 Jul 2022 01:58:23 -0400 Subject: [PATCH] fix(fetch): ByteString checks & conversion in Headers (#1560) --- lib/fetch/index.js | 4 ++-- lib/fetch/webidl.js | 5 +++-- test/fetch/client-fetch.js | 32 ++++++++++++++++++++++++++++++++ test/webidl/converters.js | 8 ++++++++ 4 files changed, 45 insertions(+), 4 deletions(-) diff --git a/lib/fetch/index.js b/lib/fetch/index.js index c313202fed5..4713ab7eb25 100644 --- a/lib/fetch/index.js +++ b/lib/fetch/index.js @@ -1946,8 +1946,8 @@ async function httpNetworkFetch ( const headers = new Headers() for (let n = 0; n < headersList.length; n += 2) { - const key = headersList[n + 0].toString() - const val = headersList[n + 1].toString() + const key = headersList[n + 0].toString('latin1') + const val = headersList[n + 1].toString('latin1') if (key.toLowerCase() === 'content-encoding') { codings = val.split(',').map((x) => x.trim()) diff --git a/lib/fetch/webidl.js b/lib/fetch/webidl.js index f9a780ccaa7..293199e8f9b 100644 --- a/lib/fetch/webidl.js +++ b/lib/fetch/webidl.js @@ -388,8 +388,9 @@ webidl.converters.DOMString = function (V, opts = {}) { return String(V) } +// Check for 0 or more characters outside of the latin1 range. // eslint-disable-next-line no-control-regex -const isNotLatin1 = /[^\u0000-\u00ff]/ +const isLatin1 = /^[\u0000-\u00ff]{0,}$/ // https://webidl.spec.whatwg.org/#es-ByteString webidl.converters.ByteString = function (V) { @@ -399,7 +400,7 @@ webidl.converters.ByteString = function (V) { // 2. If the value of any element of x is greater than // 255, then throw a TypeError. - if (isNotLatin1.test(x)) { + if (!isLatin1.test(x)) { throw new TypeError('Argument is not a ByteString') } diff --git a/test/fetch/client-fetch.js b/test/fetch/client-fetch.js index 40698c06855..90d6660dd86 100644 --- a/test/fetch/client-fetch.js +++ b/test/fetch/client-fetch.js @@ -468,3 +468,35 @@ test('do not decode redirect body', (t) => { t.strictSame(JSON.stringify(obj), await body.text()) }) }) + +test('Receiving non-Latin1 headers', async (t) => { + const ContentDisposition = [ + 'inline; filename=rock&roll.png', + 'inline; filename="rock\'n\'roll.png"', + 'inline; filename="image â\x80\x94 copy (1).png"; filename*=UTF-8\'\'image%20%E2%80%94%20copy%20(1).png', + 'inline; filename="_å\x9C\x96ç\x89\x87_ð\x9F\x96¼_image_.png"; filename*=UTF-8\'\'_%E5%9C%96%E7%89%87_%F0%9F%96%BC_image_.png', + 'inline; filename="100 % loading&perf.png"; filename*=UTF-8\'\'100%20%25%20loading%26perf.png' + ] + + const server = createServer((req, res) => { + for (let i = 0; i < ContentDisposition.length; i++) { + res.setHeader(`Content-Disposition-${i + 1}`, ContentDisposition[i]) + } + + res.end() + }).listen(0) + + t.teardown(server.close.bind(server)) + await once(server, 'listening') + + const url = `http://localhost:${server.address().port}` + const response = await fetch(url, { method: 'HEAD' }) + const cdHeaders = [...response.headers] + .filter(([k]) => k.startsWith('content-disposition')) + .map(([, v]) => v) + const lengths = cdHeaders.map(h => h.length) + + t.same(cdHeaders, ContentDisposition) + t.same(lengths, [30, 34, 94, 104, 90]) + t.end() +}) diff --git a/test/webidl/converters.js b/test/webidl/converters.js index a72bdc926fd..d1404a2ebcd 100644 --- a/test/webidl/converters.js +++ b/test/webidl/converters.js @@ -183,3 +183,11 @@ test('BufferSource', (t) => { t.end() }) + +test('ByteString', (t) => { + t.doesNotThrow(() => { + webidl.converters.ByteString('') + }) + + t.end() +})