diff options
author | Ryan Dahl <ry@tinyclouds.org> | 2021-08-11 12:27:05 +0200 |
---|---|---|
committer | GitHub <noreply@github.com> | 2021-08-11 12:27:05 +0200 |
commit | a0285e2eb88f6254f6494b0ecd1878db3a3b2a58 (patch) | |
tree | 90671b004537e20f9493fd3277ffd21d30b39a0e /ext/web/01_mimesniff.js | |
parent | 3a6994115176781b3a93d70794b1b81bc95e42b4 (diff) |
Rename extensions/ directory to ext/ (#11643)
Diffstat (limited to 'ext/web/01_mimesniff.js')
-rw-r--r-- | ext/web/01_mimesniff.js | 211 |
1 files changed, 211 insertions, 0 deletions
diff --git a/ext/web/01_mimesniff.js b/ext/web/01_mimesniff.js new file mode 100644 index 000000000..360d1ffe4 --- /dev/null +++ b/ext/web/01_mimesniff.js @@ -0,0 +1,211 @@ +// Copyright 2018-2021 the Deno authors. All rights reserved. MIT license. + +// @ts-check +/// <reference path="../../core/internal.d.ts" /> +/// <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 { + ArrayPrototypeIncludes, + Map, + MapPrototypeHas, + MapPrototypeSet, + RegExpPrototypeTest, + StringPrototypeReplaceAll, + StringPrototypeToLowerCase, + } = window.__bootstrap.primordials; + 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 = StringPrototypeReplaceAll(input, HTTP_WHITESPACE_PREFIX_RE, ""); + input = StringPrototypeReplaceAll(input, 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 === "" || !RegExpPrototypeTest(HTTP_TOKEN_CODE_POINT_RE, 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 = StringPrototypeReplaceAll(subtype, HTTP_WHITESPACE_SUFFIX_RE, ""); + + // 9. + if ( + subtype === "" || !RegExpPrototypeTest(HTTP_TOKEN_CODE_POINT_RE, subtype) + ) { + return null; + } + + // 10. + const mimeType = { + type: StringPrototypeToLowerCase(type), + subtype: StringPrototypeToLowerCase(subtype), + /** @type {Map<string, string>} */ + parameters: new Map(), + }; + + // 11. + while (position < endOfInput) { + // 11.1. + position++; + + // 11.2. + const res1 = collectSequenceOfCodepoints( + input, + position, + (c) => ArrayPrototypeIncludes(HTTP_WHITESPACE, 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 = StringPrototypeToLowerCase(parameterName); + + // 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 = StringPrototypeReplaceAll( + parameterValue, + HTTP_WHITESPACE_SUFFIX_RE, + "", + ); + + // 11.9.3. + if (parameterValue === "") continue; + } + + // 11.10. + if ( + parameterName !== "" && + RegExpPrototypeTest(HTTP_TOKEN_CODE_POINT_RE, parameterName) && + RegExpPrototypeTest( + HTTP_QUOTED_STRING_TOKEN_POINT_RE, + parameterValue, + ) && + !MapPrototypeHas(mimeType.parameters, parameterName) + ) { + MapPrototypeSet(mimeType.parameters, 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 (!RegExpPrototypeTest(HTTP_TOKEN_CODE_POINT_RE, value)) { + value = StringPrototypeReplaceAll(value, "\\", "\\\\"); + value = StringPrototypeReplaceAll(value, '"', '\\"'); + value = `"${value}"`; + } + serialization += value; + } + return serialization; + } + + window.__bootstrap.mimesniff = { parseMimeType, essence, serializeMimeType }; +})(this); |