Skip to content

Commit 56e7624

Browse files
authored
mimesniff: fix many broken tests (#2103)
* mimesniff: fix many broken tests * mimesniff: dont export this * mimesniff: undo small change * mimesniff: fix some bugs
1 parent 48f2078 commit 56e7624

File tree

3 files changed

+79
-21
lines changed

3 files changed

+79
-21
lines changed

Diff for: lib/fetch/dataURL.js

+76-19
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,18 @@
11
const assert = require('assert')
22
const { atob } = require('buffer')
3-
const { isValidHTTPToken, isomorphicDecode } = require('./util')
3+
const { isomorphicDecode } = require('./util')
44

55
const encoder = new TextEncoder()
66

7-
// Regex
8-
const HTTP_TOKEN_CODEPOINTS = /^[!#$%&'*+-.^_|~A-z0-9]+$/
7+
/**
8+
* @see https://mimesniff.spec.whatwg.org/#http-token-code-point
9+
*/
10+
const HTTP_TOKEN_CODEPOINTS = /^[!#$%&'*+-.^_|~A-Za-z0-9]+$/
911
const HTTP_WHITESPACE_REGEX = /(\u000A|\u000D|\u0009|\u0020)/ // eslint-disable-line
10-
// https://mimesniff.spec.whatwg.org/#http-quoted-string-token-code-point
11-
const HTTP_QUOTED_STRING_TOKENS = /^(\u0009|\x{0020}-\x{007E}|\x{0080}-\x{00FF})+$/ // eslint-disable-line
12+
/**
13+
* @see https://mimesniff.spec.whatwg.org/#http-quoted-string-token-code-point
14+
*/
15+
const HTTP_QUOTED_STRING_TOKENS = /[\u0009|\u0020-\u007E|\u0080-\u00FF]/ // eslint-disable-line
1216

1317
// https://fetch.spec.whatwg.org/#data-url-processor
1418
/** @param {URL} dataURL */
@@ -38,14 +42,12 @@ function dataURLProcessor (dataURL) {
3842

3943
// 6. Strip leading and trailing ASCII whitespace
4044
// from mimeType.
41-
// Note: This will only remove U+0020 SPACE code
42-
// points, if any.
4345
// Undici implementation note: we need to store the
4446
// length because if the mimetype has spaces removed,
4547
// the wrong amount will be sliced from the input in
4648
// step #9
4749
const mimeTypeLength = mimeType.length
48-
mimeType = mimeType.replace(/^(\u0020)+|(\u0020)+$/g, '')
50+
mimeType = removeASCIIWhitespace(mimeType, true, true)
4951

5052
// 7. If position is past the end of input, then
5153
// return failure
@@ -233,7 +235,7 @@ function percentDecode (input) {
233235
function parseMIMEType (input) {
234236
// 1. Remove any leading and trailing HTTP whitespace
235237
// from input.
236-
input = input.trim()
238+
input = removeHTTPWhitespace(input, true, true)
237239

238240
// 2. Let position be a position variable for input,
239241
// initially pointing at the start of input.
@@ -274,25 +276,28 @@ function parseMIMEType (input) {
274276
)
275277

276278
// 8. Remove any trailing HTTP whitespace from subtype.
277-
subtype = subtype.trimEnd()
279+
subtype = removeHTTPWhitespace(subtype, false, true)
278280

279281
// 9. If subtype is the empty string or does not solely
280282
// contain HTTP token code points, then return failure.
281283
if (subtype.length === 0 || !HTTP_TOKEN_CODEPOINTS.test(subtype)) {
282284
return 'failure'
283285
}
284286

287+
const typeLowercase = type.toLowerCase()
288+
const subtypeLowercase = subtype.toLowerCase()
289+
285290
// 10. Let mimeType be a new MIME type record whose type
286291
// is type, in ASCII lowercase, and subtype is subtype,
287292
// in ASCII lowercase.
288293
// https://mimesniff.spec.whatwg.org/#mime-type
289294
const mimeType = {
290-
type: type.toLowerCase(),
291-
subtype: subtype.toLowerCase(),
295+
type: typeLowercase,
296+
subtype: subtypeLowercase,
292297
/** @type {Map<string, string>} */
293298
parameters: new Map(),
294299
// https://mimesniff.spec.whatwg.org/#mime-type-essence
295-
essence: `${type}/${subtype}`
300+
essence: `${typeLowercase}/${subtypeLowercase}`
296301
}
297302

298303
// 11. While position is not past the end of input:
@@ -370,8 +375,7 @@ function parseMIMEType (input) {
370375
)
371376

372377
// 2. Remove any trailing HTTP whitespace from parameterValue.
373-
// Note: it says "trailing" whitespace; leading is fine.
374-
parameterValue = parameterValue.trimEnd()
378+
parameterValue = removeHTTPWhitespace(parameterValue, false, true)
375379

376380
// 3. If parameterValue is the empty string, then continue.
377381
if (parameterValue.length === 0) {
@@ -388,7 +392,7 @@ function parseMIMEType (input) {
388392
if (
389393
parameterName.length !== 0 &&
390394
HTTP_TOKEN_CODEPOINTS.test(parameterName) &&
391-
!HTTP_QUOTED_STRING_TOKENS.test(parameterValue) &&
395+
(parameterValue.length === 0 || HTTP_QUOTED_STRING_TOKENS.test(parameterValue)) &&
392396
!mimeType.parameters.has(parameterName)
393397
) {
394398
mimeType.parameters.set(parameterName, parameterValue)
@@ -522,11 +526,11 @@ function collectAnHTTPQuotedString (input, position, extractValue) {
522526
*/
523527
function serializeAMimeType (mimeType) {
524528
assert(mimeType !== 'failure')
525-
const { type, subtype, parameters } = mimeType
529+
const { parameters, essence } = mimeType
526530

527531
// 1. Let serialization be the concatenation of mimeType’s
528532
// type, U+002F (/), and mimeType’s subtype.
529-
let serialization = `${type}/${subtype}`
533+
let serialization = essence
530534

531535
// 2. For each name → value of mimeType’s parameters:
532536
for (let [name, value] of parameters.entries()) {
@@ -541,7 +545,7 @@ function serializeAMimeType (mimeType) {
541545

542546
// 4. If value does not solely contain HTTP token code
543547
// points or value is the empty string, then:
544-
if (!isValidHTTPToken(value)) {
548+
if (!HTTP_TOKEN_CODEPOINTS.test(value)) {
545549
// 1. Precede each occurence of U+0022 (") or
546550
// U+005C (\) in value with U+005C (\).
547551
value = value.replace(/(\\|")/g, '\\$1')
@@ -561,6 +565,59 @@ function serializeAMimeType (mimeType) {
561565
return serialization
562566
}
563567

568+
/**
569+
* @see https://fetch.spec.whatwg.org/#http-whitespace
570+
* @param {string} char
571+
*/
572+
function isHTTPWhiteSpace (char) {
573+
return char === '\r' || char === '\n' || char === '\t' || char === ' '
574+
}
575+
576+
/**
577+
* @see https://fetch.spec.whatwg.org/#http-whitespace
578+
* @param {string} str
579+
*/
580+
function removeHTTPWhitespace (str, leading = true, trailing = true) {
581+
let lead = 0
582+
let trail = str.length - 1
583+
584+
if (leading) {
585+
for (; lead < str.length && isHTTPWhiteSpace(str[lead]); lead++);
586+
}
587+
588+
if (trailing) {
589+
for (; trail > 0 && isHTTPWhiteSpace(str[trail]); trail--);
590+
}
591+
592+
return str.slice(lead, trail + 1)
593+
}
594+
595+
/**
596+
* @see https://infra.spec.whatwg.org/#ascii-whitespace
597+
* @param {string} char
598+
*/
599+
function isASCIIWhitespace (char) {
600+
return char === '\r' || char === '\n' || char === '\t' || char === '\f' || char === ' '
601+
}
602+
603+
/**
604+
* @see https://infra.spec.whatwg.org/#strip-leading-and-trailing-ascii-whitespace
605+
*/
606+
function removeASCIIWhitespace (str, leading = true, trailing = true) {
607+
let lead = 0
608+
let trail = str.length - 1
609+
610+
if (leading) {
611+
for (; lead < str.length && isASCIIWhitespace(str[lead]); lead++);
612+
}
613+
614+
if (trailing) {
615+
for (; trail > 0 && isASCIIWhitespace(str[trail]); trail--);
616+
}
617+
618+
return str.slice(lead, trail + 1)
619+
}
620+
564621
module.exports = {
565622
dataURLProcessor,
566623
URLSerializer,

Diff for: lib/fetch/response.js

+1-1
Original file line numberDiff line numberDiff line change
@@ -467,7 +467,7 @@ function initializeResponse (response, init, body) {
467467

468468
// 5. If init["headers"] exists, then fill response’s headers with init["headers"].
469469
if ('headers' in init && init.headers != null) {
470-
fill(response[kState].headersList, init.headers)
470+
fill(response[kHeaders], init.headers)
471471
}
472472

473473
// 6. If body was given, then:

Diff for: test/wpt/runner/runner.mjs

+2-1
Original file line numberDiff line numberDiff line change
@@ -150,8 +150,9 @@ export class WPTRunner extends EventEmitter {
150150
return [test, code, meta]
151151
})
152152

153+
console.log('='.repeat(96))
154+
153155
for (const [test, code, meta] of files) {
154-
console.log('='.repeat(96))
155156
console.log(`Started ${test}`)
156157

157158
const status = resolveStatusPath(test, this.#status)

0 commit comments

Comments
 (0)