summaryrefslogtreecommitdiff
path: root/extensions/web/01_mimesniff.js
diff options
context:
space:
mode:
Diffstat (limited to 'extensions/web/01_mimesniff.js')
-rw-r--r--extensions/web/01_mimesniff.js190
1 files changed, 190 insertions, 0 deletions
diff --git a/extensions/web/01_mimesniff.js b/extensions/web/01_mimesniff.js
new file mode 100644
index 000000000..b42dd1409
--- /dev/null
+++ b/extensions/web/01_mimesniff.js
@@ -0,0 +1,190 @@
+// 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,
+ HTTP_WHITESPACE,
+ HTTP_WHITESPACE_PREFIX_RE,
+ HTTP_WHITESPACE_SUFFIX_RE,
+ HTTP_QUOTED_STRING_TOKEN_POINT_RE,
+ HTTP_TOKEN_CODE_POINT_RE,
+ collectHttpQuotedString,
+ } = window.__bootstrap.infra;
+
+ /**
+ * @typedef MimeType
+ * @property {string} type
+ * @property {string} subtype
+ * @property {Map<string,string>} parameters
+ */
+
+ /**
+ * @param {string} input
+ * @returns {MimeType | null}
+ */
+ function parseMimeType(input) {
+ // 1.
+ input = input.replaceAll(HTTP_WHITESPACE_PREFIX_RE, "");
+ input = input.replaceAll(HTTP_WHITESPACE_SUFFIX_RE, "");
+
+ // 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(HTTP_WHITESPACE_SUFFIX_RE, "");
+
+ // 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(
+ HTTP_WHITESPACE_SUFFIX_RE,
+ "",
+ );
+
+ // 11.9.3.
+ if (parameterValue === "") continue;
+ }
+
+ // 11.10.
+ 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;
+ }
+
+ /**
+ * @param {MimeType} mimeType
+ * @returns {string}
+ */
+ function essence(mimeType) {
+ return `${mimeType.type}/${mimeType.subtype}`;
+ }
+
+ /**
+ * @param {MimeType} mimeType
+ * @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 };
+})(this);