mirror of
https://github.com/denoland/deno.git
synced 2024-10-31 09:14:20 -04:00
243 lines
5.7 KiB
JavaScript
243 lines
5.7 KiB
JavaScript
|
// Copyright 2018-2021 the Deno authors. All rights reserved. MIT license.
|
||
|
|
||
|
// @ts-check
|
||
|
/// <reference path="../../core/lib.deno_core.d.ts" />
|
||
|
/// <reference path="../web/internal.d.ts" />
|
||
|
/// <reference path="../web/lib.deno_web.d.ts" />
|
||
|
|
||
|
"use strict";
|
||
|
|
||
|
((window) => {
|
||
|
const { collectSequenceOfCodepoints } = window.__bootstrap.infra;
|
||
|
|
||
|
const HTTP_TAB_OR_SPACE = ["\u0009", "\u0020"];
|
||
|
const HTTP_WHITESPACE = ["\u000A", "\u000D", ...HTTP_TAB_OR_SPACE];
|
||
|
|
||
|
const ASCII_DIGIT = ["\u0030-\u0039"];
|
||
|
const ASCII_UPPER_ALPHA = ["\u0041-\u005A"];
|
||
|
const ASCII_LOWER_ALPHA = ["\u0061-\u007A"];
|
||
|
const ASCII_ALPHA = [...ASCII_UPPER_ALPHA, ...ASCII_LOWER_ALPHA];
|
||
|
const ASCII_ALPHANUMERIC = [...ASCII_DIGIT, ...ASCII_ALPHA];
|
||
|
const HTTP_TOKEN_CODE_POINT = [
|
||
|
"\u0021",
|
||
|
"\u0023",
|
||
|
"\u0025",
|
||
|
"\u0026",
|
||
|
"\u0027",
|
||
|
"\u002A",
|
||
|
"\u002B",
|
||
|
"\u002D",
|
||
|
"\u002E",
|
||
|
"\u005E",
|
||
|
"\u005F",
|
||
|
"\u0060",
|
||
|
"\u007C",
|
||
|
"\u007E",
|
||
|
...ASCII_ALPHANUMERIC,
|
||
|
];
|
||
|
const HTTP_TOKEN_CODE_POINT_RE = new RegExp(`^[${HTTP_TOKEN_CODE_POINT}]+$`);
|
||
|
const HTTP_QUOTED_STRING_TOKEN_POINT = [
|
||
|
"\u0009",
|
||
|
"\u0020-\u007E",
|
||
|
"\u0080-\u00FF",
|
||
|
];
|
||
|
const HTTP_QUOTED_STRING_TOKEN_POINT_RE = new RegExp(
|
||
|
`^[${HTTP_QUOTED_STRING_TOKEN_POINT}]+$`,
|
||
|
);
|
||
|
|
||
|
/**
|
||
|
* https://fetch.spec.whatwg.org/#collect-an-http-quoted-string
|
||
|
* @param {string} input
|
||
|
* @param {number} position
|
||
|
* @param {boolean} extractValue
|
||
|
* @returns {{result: string, position: number}}
|
||
|
*/
|
||
|
function collectHttpQuotedString(input, position, extractValue) {
|
||
|
// 1.
|
||
|
const positionStart = position;
|
||
|
// 2.
|
||
|
let value = "";
|
||
|
// 3.
|
||
|
if (input[position] !== "\u0022") throw new Error('must be "');
|
||
|
// 4.
|
||
|
position++;
|
||
|
// 5.
|
||
|
while (true) {
|
||
|
// 5.1.
|
||
|
const res = collectSequenceOfCodepoints(
|
||
|
input,
|
||
|
position,
|
||
|
(c) => c !== "\u0022" && c !== "\u005C",
|
||
|
);
|
||
|
value += res.result;
|
||
|
position = res.position;
|
||
|
// 5.2.
|
||
|
if (position >= input.length) break;
|
||
|
// 5.3.
|
||
|
const quoteOrBackslash = input[position];
|
||
|
// 5.4.
|
||
|
position++;
|
||
|
// 5.5.
|
||
|
if (quoteOrBackslash === "\u005C") {
|
||
|
// 5.5.1.
|
||
|
if (position >= input.length) {
|
||
|
value += "\u005C";
|
||
|
break;
|
||
|
}
|
||
|
// 5.5.2.
|
||
|
value += input[position];
|
||
|
// 5.5.3.
|
||
|
position++;
|
||
|
} else { // 5.6.
|
||
|
// 5.6.1
|
||
|
if (input[position] !== "\u0022") throw new Error('must be "');
|
||
|
// 5.6.2
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
// 6.
|
||
|
if (extractValue) return { result: value, position };
|
||
|
// 7.
|
||
|
return { result: input.substring(positionStart, position + 1), position };
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* @param {string} input
|
||
|
*/
|
||
|
function parseMimeType(input) {
|
||
|
// 1.
|
||
|
input = input.replaceAll(new RegExp(`^[${HTTP_WHITESPACE}]+`, "g"), "");
|
||
|
input = input.replaceAll(new RegExp(`[${HTTP_WHITESPACE}]+$`, "g"), "");
|
||
|
|
||
|
// 2.
|
||
|
let position = 0;
|
||
|
const endOfInput = input.length;
|
||
|
|
||
|
// 3.
|
||
|
const res1 = collectSequenceOfCodepoints(
|
||
|
input,
|
||
|
position,
|
||
|
(c) => c != "\u002F",
|
||
|
);
|
||
|
const type = res1.result;
|
||
|
position = res1.position;
|
||
|
|
||
|
// 4.
|
||
|
if (type === "" || !HTTP_TOKEN_CODE_POINT_RE.test(type)) {
|
||
|
return null;
|
||
|
}
|
||
|
|
||
|
// 5.
|
||
|
if (position >= endOfInput) return null;
|
||
|
|
||
|
// 6.
|
||
|
position++;
|
||
|
|
||
|
// 7.
|
||
|
const res2 = collectSequenceOfCodepoints(
|
||
|
input,
|
||
|
position,
|
||
|
(c) => c != "\u003B",
|
||
|
);
|
||
|
let subtype = res2.result;
|
||
|
position = res2.position;
|
||
|
|
||
|
// 8.
|
||
|
subtype = subtype.replaceAll(new RegExp(`[${HTTP_WHITESPACE}]+$`, "g"), "");
|
||
|
|
||
|
// 9.
|
||
|
if (subtype === "" || !HTTP_TOKEN_CODE_POINT_RE.test(subtype)) {
|
||
|
return null;
|
||
|
}
|
||
|
|
||
|
// 10.
|
||
|
const mimeType = {
|
||
|
type: type.toLowerCase(),
|
||
|
subtype: subtype.toLowerCase(),
|
||
|
/** @type {Map<string, string>} */
|
||
|
parameters: new Map(),
|
||
|
};
|
||
|
|
||
|
// 11.
|
||
|
while (position < endOfInput) {
|
||
|
// 11.1.
|
||
|
position++;
|
||
|
|
||
|
// 11.2.
|
||
|
const res1 = collectSequenceOfCodepoints(
|
||
|
input,
|
||
|
position,
|
||
|
(c) => HTTP_WHITESPACE.includes(c),
|
||
|
);
|
||
|
position = res1.position;
|
||
|
|
||
|
// 11.3.
|
||
|
const res2 = collectSequenceOfCodepoints(
|
||
|
input,
|
||
|
position,
|
||
|
(c) => c !== "\u003B" && c !== "\u003D",
|
||
|
);
|
||
|
let parameterName = res2.result;
|
||
|
position = res2.position;
|
||
|
|
||
|
// 11.4.
|
||
|
parameterName = parameterName.toLowerCase();
|
||
|
|
||
|
// 11.5.
|
||
|
if (position < endOfInput) {
|
||
|
if (input[position] == "\u003B") continue;
|
||
|
position++;
|
||
|
}
|
||
|
|
||
|
// 11.6.
|
||
|
if (position >= endOfInput) break;
|
||
|
|
||
|
// 11.7.
|
||
|
let parameterValue = null;
|
||
|
|
||
|
// 11.8.
|
||
|
if (input[position] == "\u0022") {
|
||
|
// 11.8.1.
|
||
|
const res = collectHttpQuotedString(input, position, true);
|
||
|
parameterValue = res.result;
|
||
|
position = res.position;
|
||
|
|
||
|
// 11.8.2.
|
||
|
position++;
|
||
|
} else { // 11.9.
|
||
|
// 11.9.1.
|
||
|
const res = collectSequenceOfCodepoints(
|
||
|
input,
|
||
|
position,
|
||
|
(c) => c !== "\u003B",
|
||
|
);
|
||
|
parameterValue = res.result;
|
||
|
position = res.position;
|
||
|
|
||
|
// 11.9.2.
|
||
|
parameterValue = parameterValue.replaceAll(
|
||
|
new RegExp(`[${HTTP_WHITESPACE}]+$`, "g"),
|
||
|
"",
|
||
|
);
|
||
|
|
||
|
// 11.9.3.
|
||
|
if (parameterValue === "") continue;
|
||
|
}
|
||
|
|
||
|
// 11.9.
|
||
|
if (
|
||
|
parameterName !== "" && HTTP_TOKEN_CODE_POINT_RE.test(parameterName) &&
|
||
|
HTTP_QUOTED_STRING_TOKEN_POINT_RE.test(parameterValue) &&
|
||
|
!mimeType.parameters.has(parameterName)
|
||
|
) {
|
||
|
mimeType.parameters.set(parameterName, parameterValue);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// 12.
|
||
|
return mimeType;
|
||
|
}
|
||
|
|
||
|
window.__bootstrap.mimesniff = { parseMimeType };
|
||
|
})(this);
|