Skip to content

Commit f4bec9e

Browse files
committed
fix(fetch): ByteString checks & conversion in Headers
1 parent 0ab421f commit f4bec9e

4 files changed

Lines changed: 45 additions & 4 deletions

File tree

lib/fetch/index.js

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1946,8 +1946,8 @@ async function httpNetworkFetch (
19461946

19471947
const headers = new Headers()
19481948
for (let n = 0; n < headersList.length; n += 2) {
1949-
const key = headersList[n + 0].toString()
1950-
const val = headersList[n + 1].toString()
1949+
const key = headersList[n + 0].toString('latin1')
1950+
const val = headersList[n + 1].toString('latin1')
19511951

19521952
if (key.toLowerCase() === 'content-encoding') {
19531953
codings = val.split(',').map((x) => x.trim())

lib/fetch/webidl.js

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -388,8 +388,9 @@ webidl.converters.DOMString = function (V, opts = {}) {
388388
return String(V)
389389
}
390390

391+
// Check for 0 or more characters outside of the latin1 range.
391392
// eslint-disable-next-line no-control-regex
392-
const isNotLatin1 = /[^\u0000-\u00ff]/
393+
const isLatin1 = /^[\u0000-\u00ff]{0,}$/
393394

394395
// https://webidl.spec.whatwg.org/#es-ByteString
395396
webidl.converters.ByteString = function (V) {
@@ -399,7 +400,7 @@ webidl.converters.ByteString = function (V) {
399400

400401
// 2. If the value of any element of x is greater than
401402
// 255, then throw a TypeError.
402-
if (isNotLatin1.test(x)) {
403+
if (!isLatin1.test(x)) {
403404
throw new TypeError('Argument is not a ByteString')
404405
}
405406

test/fetch/client-fetch.js

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -468,3 +468,35 @@ test('do not decode redirect body', (t) => {
468468
t.strictSame(JSON.stringify(obj), await body.text())
469469
})
470470
})
471+
472+
test('Receiving non-Latin1 headers', async (t) => {
473+
const ContentDisposition = [
474+
'inline; filename=rock&roll.png',
475+
'inline; filename="rock\'n\'roll.png"',
476+
'inline; filename="image â\x80\x94 copy (1).png"; filename*=UTF-8\'\'image%20%E2%80%94%20copy%20(1).png',
477+
'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',
478+
'inline; filename="100 % loading&perf.png"; filename*=UTF-8\'\'100%20%25%20loading%26perf.png'
479+
]
480+
481+
const server = createServer((req, res) => {
482+
for (let i = 0; i < ContentDisposition.length; i++) {
483+
res.setHeader(`Content-Disposition-${i + 1}`, ContentDisposition[i])
484+
}
485+
486+
res.end()
487+
}).listen(0)
488+
489+
t.teardown(server.close.bind(server))
490+
await once(server, 'listening')
491+
492+
const url = `http://localhost:${server.address().port}`
493+
const response = await fetch(url, { method: 'HEAD' })
494+
const cdHeaders = [...response.headers]
495+
.filter(([k]) => k.startsWith('content-disposition'))
496+
.map(([, v]) => v)
497+
const lengths = cdHeaders.map(h => h.length)
498+
499+
t.same(cdHeaders, ContentDisposition)
500+
t.same(lengths, [30, 34, 94, 104, 90])
501+
t.end()
502+
})

test/webidl/converters.js

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -183,3 +183,11 @@ test('BufferSource', (t) => {
183183

184184
t.end()
185185
})
186+
187+
test('ByteString', (t) => {
188+
t.doesNotThrow(() => {
189+
webidl.converters.ByteString('')
190+
})
191+
192+
t.end()
193+
})

0 commit comments

Comments
 (0)