2021-04-08 09:05:08 -04:00
|
|
|
// 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) => {
|
2021-04-18 19:00:13 -04:00
|
|
|
const {
|
|
|
|
collectSequenceOfCodepoints,
|
|
|
|
HTTP_WHITESPACE,
|
|
|
|
HTTP_WHITESPACE_PREFIX_RE,
|
|
|
|
HTTP_WHITESPACE_SUFFIX_RE,
|
|
|
|
HTTP_QUOTED_STRING_TOKEN_POINT_RE,
|
|
|
|
HTTP_TOKEN_CODE_POINT_RE,
|
2021-04-20 08:47:22 -04:00
|
|
|
collectHttpQuotedString,
|
2021-04-18 19:00:13 -04:00
|
|
|
} = window.__bootstrap.infra;
|
2021-04-08 09:05:08 -04:00
|
|
|
|
2021-04-18 19:00:13 -04:00
|
|
|
/**
|
2021-04-28 10:08:51 -04:00
|
|
|
* @typedef MimeType
|
2021-04-18 19:00:13 -04:00
|
|
|
* @property {string} type
|
|
|
|
* @property {string} subtype
|
|
|
|
* @property {Map<string,string>} parameters
|
|
|
|
*/
|
|
|
|
|
2021-04-08 09:05:08 -04:00
|
|
|
/**
|
|
|
|
* @param {string} input
|
2021-04-18 19:00:13 -04:00
|
|
|
* @returns {MimeType | null}
|
2021-04-08 09:05:08 -04:00
|
|
|
*/
|
|
|
|
function parseMimeType(input) {
|
|
|
|
// 1.
|
2021-04-14 16:49:16 -04:00
|
|
|
input = input.replaceAll(HTTP_WHITESPACE_PREFIX_RE, "");
|
|
|
|
input = input.replaceAll(HTTP_WHITESPACE_SUFFIX_RE, "");
|
2021-04-08 09:05:08 -04:00
|
|
|
|
|
|
|
// 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.
|
2021-04-14 16:49:16 -04:00
|
|
|
if (type === "" || !HTTP_TOKEN_CODE_POINT_RE.test(type)) return null;
|
2021-04-08 09:05:08 -04:00
|
|
|
|
|
|
|
// 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.
|
2021-04-14 16:49:16 -04:00
|
|
|
subtype = subtype.replaceAll(HTTP_WHITESPACE_SUFFIX_RE, "");
|
2021-04-08 09:05:08 -04:00
|
|
|
|
|
|
|
// 9.
|
2021-04-14 16:49:16 -04:00
|
|
|
if (subtype === "" || !HTTP_TOKEN_CODE_POINT_RE.test(subtype)) return null;
|
2021-04-08 09:05:08 -04:00
|
|
|
|
|
|
|
// 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.
|
2021-04-20 08:47:22 -04:00
|
|
|
if (input[position] === "\u0022") {
|
2021-04-08 09:05:08 -04:00
|
|
|
// 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(
|
2021-04-14 16:49:16 -04:00
|
|
|
HTTP_WHITESPACE_SUFFIX_RE,
|
2021-04-08 09:05:08 -04:00
|
|
|
"",
|
|
|
|
);
|
|
|
|
|
|
|
|
// 11.9.3.
|
|
|
|
if (parameterValue === "") continue;
|
|
|
|
}
|
|
|
|
|
2021-04-14 16:49:16 -04:00
|
|
|
// 11.10.
|
2021-04-08 09:05:08 -04:00
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
2021-04-20 08:47:22 -04:00
|
|
|
/**
|
2021-04-28 10:08:51 -04:00
|
|
|
* @param {MimeType} mimeType
|
2021-04-20 08:47:22 -04:00
|
|
|
* @returns {string}
|
|
|
|
*/
|
|
|
|
function essence(mimeType) {
|
|
|
|
return `${mimeType.type}/${mimeType.subtype}`;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
2021-04-28 10:08:51 -04:00
|
|
|
* @param {MimeType} mimeType
|
2021-04-20 08:47:22 -04:00
|
|
|
* @returns {string}
|
|
|
|
*/
|
|
|
|
function serializeMimeType(mimeType) {
|
|
|
|
let serialization = essence(mimeType);
|
|
|
|
for (const param of mimeType.parameters) {
|
|
|
|
serialization += `;${param[0]}=`;
|
|
|
|
let value = param[1];
|
|
|
|
if (!HTTP_TOKEN_CODE_POINT_RE.test(value)) {
|
|
|
|
value = value.replaceAll("\\", "\\\\");
|
|
|
|
value = value.replaceAll('"', '\\"');
|
|
|
|
value = `"${value}"`;
|
|
|
|
}
|
|
|
|
serialization += value;
|
|
|
|
}
|
|
|
|
return serialization;
|
|
|
|
}
|
|
|
|
|
|
|
|
window.__bootstrap.mimesniff = { parseMimeType, essence, serializeMimeType };
|
2021-04-08 09:05:08 -04:00
|
|
|
})(this);
|