Spaces:
Runtime error
Runtime error
| ; | |
| function parseContentType(str) { | |
| if (str.length === 0) | |
| return; | |
| const params = Object.create(null); | |
| let i = 0; | |
| // Parse type | |
| for (; i < str.length; ++i) { | |
| const code = str.charCodeAt(i); | |
| if (TOKEN[code] !== 1) { | |
| if (code !== 47/* '/' */ || i === 0) | |
| return; | |
| break; | |
| } | |
| } | |
| // Check for type without subtype | |
| if (i === str.length) | |
| return; | |
| const type = str.slice(0, i).toLowerCase(); | |
| // Parse subtype | |
| const subtypeStart = ++i; | |
| for (; i < str.length; ++i) { | |
| const code = str.charCodeAt(i); | |
| if (TOKEN[code] !== 1) { | |
| // Make sure we have a subtype | |
| if (i === subtypeStart) | |
| return; | |
| if (parseContentTypeParams(str, i, params) === undefined) | |
| return; | |
| break; | |
| } | |
| } | |
| // Make sure we have a subtype | |
| if (i === subtypeStart) | |
| return; | |
| const subtype = str.slice(subtypeStart, i).toLowerCase(); | |
| return { type, subtype, params }; | |
| } | |
| function parseContentTypeParams(str, i, params) { | |
| while (i < str.length) { | |
| // Consume whitespace | |
| for (; i < str.length; ++i) { | |
| const code = str.charCodeAt(i); | |
| if (code !== 32/* ' ' */ && code !== 9/* '\t' */) | |
| break; | |
| } | |
| // Ended on whitespace | |
| if (i === str.length) | |
| break; | |
| // Check for malformed parameter | |
| if (str.charCodeAt(i++) !== 59/* ';' */) | |
| return; | |
| // Consume whitespace | |
| for (; i < str.length; ++i) { | |
| const code = str.charCodeAt(i); | |
| if (code !== 32/* ' ' */ && code !== 9/* '\t' */) | |
| break; | |
| } | |
| // Ended on whitespace (malformed) | |
| if (i === str.length) | |
| return; | |
| let name; | |
| const nameStart = i; | |
| // Parse parameter name | |
| for (; i < str.length; ++i) { | |
| const code = str.charCodeAt(i); | |
| if (TOKEN[code] !== 1) { | |
| if (code !== 61/* '=' */) | |
| return; | |
| break; | |
| } | |
| } | |
| // No value (malformed) | |
| if (i === str.length) | |
| return; | |
| name = str.slice(nameStart, i); | |
| ++i; // Skip over '=' | |
| // No value (malformed) | |
| if (i === str.length) | |
| return; | |
| let value = ''; | |
| let valueStart; | |
| if (str.charCodeAt(i) === 34/* '"' */) { | |
| valueStart = ++i; | |
| let escaping = false; | |
| // Parse quoted value | |
| for (; i < str.length; ++i) { | |
| const code = str.charCodeAt(i); | |
| if (code === 92/* '\\' */) { | |
| if (escaping) { | |
| valueStart = i; | |
| escaping = false; | |
| } else { | |
| value += str.slice(valueStart, i); | |
| escaping = true; | |
| } | |
| continue; | |
| } | |
| if (code === 34/* '"' */) { | |
| if (escaping) { | |
| valueStart = i; | |
| escaping = false; | |
| continue; | |
| } | |
| value += str.slice(valueStart, i); | |
| break; | |
| } | |
| if (escaping) { | |
| valueStart = i - 1; | |
| escaping = false; | |
| } | |
| // Invalid unescaped quoted character (malformed) | |
| if (QDTEXT[code] !== 1) | |
| return; | |
| } | |
| // No end quote (malformed) | |
| if (i === str.length) | |
| return; | |
| ++i; // Skip over double quote | |
| } else { | |
| valueStart = i; | |
| // Parse unquoted value | |
| for (; i < str.length; ++i) { | |
| const code = str.charCodeAt(i); | |
| if (TOKEN[code] !== 1) { | |
| // No value (malformed) | |
| if (i === valueStart) | |
| return; | |
| break; | |
| } | |
| } | |
| value = str.slice(valueStart, i); | |
| } | |
| name = name.toLowerCase(); | |
| if (params[name] === undefined) | |
| params[name] = value; | |
| } | |
| return params; | |
| } | |
| function parseDisposition(str, defDecoder) { | |
| if (str.length === 0) | |
| return; | |
| const params = Object.create(null); | |
| let i = 0; | |
| for (; i < str.length; ++i) { | |
| const code = str.charCodeAt(i); | |
| if (TOKEN[code] !== 1) { | |
| if (parseDispositionParams(str, i, params, defDecoder) === undefined) | |
| return; | |
| break; | |
| } | |
| } | |
| const type = str.slice(0, i).toLowerCase(); | |
| return { type, params }; | |
| } | |
| function parseDispositionParams(str, i, params, defDecoder) { | |
| while (i < str.length) { | |
| // Consume whitespace | |
| for (; i < str.length; ++i) { | |
| const code = str.charCodeAt(i); | |
| if (code !== 32/* ' ' */ && code !== 9/* '\t' */) | |
| break; | |
| } | |
| // Ended on whitespace | |
| if (i === str.length) | |
| break; | |
| // Check for malformed parameter | |
| if (str.charCodeAt(i++) !== 59/* ';' */) | |
| return; | |
| // Consume whitespace | |
| for (; i < str.length; ++i) { | |
| const code = str.charCodeAt(i); | |
| if (code !== 32/* ' ' */ && code !== 9/* '\t' */) | |
| break; | |
| } | |
| // Ended on whitespace (malformed) | |
| if (i === str.length) | |
| return; | |
| let name; | |
| const nameStart = i; | |
| // Parse parameter name | |
| for (; i < str.length; ++i) { | |
| const code = str.charCodeAt(i); | |
| if (TOKEN[code] !== 1) { | |
| if (code === 61/* '=' */) | |
| break; | |
| return; | |
| } | |
| } | |
| // No value (malformed) | |
| if (i === str.length) | |
| return; | |
| let value = ''; | |
| let valueStart; | |
| let charset; | |
| //~ let lang; | |
| name = str.slice(nameStart, i); | |
| if (name.charCodeAt(name.length - 1) === 42/* '*' */) { | |
| // Extended value | |
| const charsetStart = ++i; | |
| // Parse charset name | |
| for (; i < str.length; ++i) { | |
| const code = str.charCodeAt(i); | |
| if (CHARSET[code] !== 1) { | |
| if (code !== 39/* '\'' */) | |
| return; | |
| break; | |
| } | |
| } | |
| // Incomplete charset (malformed) | |
| if (i === str.length) | |
| return; | |
| charset = str.slice(charsetStart, i); | |
| ++i; // Skip over the '\'' | |
| //~ const langStart = ++i; | |
| // Parse language name | |
| for (; i < str.length; ++i) { | |
| const code = str.charCodeAt(i); | |
| if (code === 39/* '\'' */) | |
| break; | |
| } | |
| // Incomplete language (malformed) | |
| if (i === str.length) | |
| return; | |
| //~ lang = str.slice(langStart, i); | |
| ++i; // Skip over the '\'' | |
| // No value (malformed) | |
| if (i === str.length) | |
| return; | |
| valueStart = i; | |
| let encode = 0; | |
| // Parse value | |
| for (; i < str.length; ++i) { | |
| const code = str.charCodeAt(i); | |
| if (EXTENDED_VALUE[code] !== 1) { | |
| if (code === 37/* '%' */) { | |
| let hexUpper; | |
| let hexLower; | |
| if (i + 2 < str.length | |
| && (hexUpper = HEX_VALUES[str.charCodeAt(i + 1)]) !== -1 | |
| && (hexLower = HEX_VALUES[str.charCodeAt(i + 2)]) !== -1) { | |
| const byteVal = (hexUpper << 4) + hexLower; | |
| value += str.slice(valueStart, i); | |
| value += String.fromCharCode(byteVal); | |
| i += 2; | |
| valueStart = i + 1; | |
| if (byteVal >= 128) | |
| encode = 2; | |
| else if (encode === 0) | |
| encode = 1; | |
| continue; | |
| } | |
| // '%' disallowed in non-percent encoded contexts (malformed) | |
| return; | |
| } | |
| break; | |
| } | |
| } | |
| value += str.slice(valueStart, i); | |
| value = convertToUTF8(value, charset, encode); | |
| if (value === undefined) | |
| return; | |
| } else { | |
| // Non-extended value | |
| ++i; // Skip over '=' | |
| // No value (malformed) | |
| if (i === str.length) | |
| return; | |
| if (str.charCodeAt(i) === 34/* '"' */) { | |
| valueStart = ++i; | |
| let escaping = false; | |
| // Parse quoted value | |
| for (; i < str.length; ++i) { | |
| const code = str.charCodeAt(i); | |
| if (code === 92/* '\\' */) { | |
| if (escaping) { | |
| valueStart = i; | |
| escaping = false; | |
| } else { | |
| value += str.slice(valueStart, i); | |
| escaping = true; | |
| } | |
| continue; | |
| } | |
| if (code === 34/* '"' */) { | |
| if (escaping) { | |
| valueStart = i; | |
| escaping = false; | |
| continue; | |
| } | |
| value += str.slice(valueStart, i); | |
| break; | |
| } | |
| if (escaping) { | |
| valueStart = i - 1; | |
| escaping = false; | |
| } | |
| // Invalid unescaped quoted character (malformed) | |
| if (QDTEXT[code] !== 1) | |
| return; | |
| } | |
| // No end quote (malformed) | |
| if (i === str.length) | |
| return; | |
| ++i; // Skip over double quote | |
| } else { | |
| valueStart = i; | |
| // Parse unquoted value | |
| for (; i < str.length; ++i) { | |
| const code = str.charCodeAt(i); | |
| if (TOKEN[code] !== 1) { | |
| // No value (malformed) | |
| if (i === valueStart) | |
| return; | |
| break; | |
| } | |
| } | |
| value = str.slice(valueStart, i); | |
| } | |
| value = defDecoder(value, 2); | |
| if (value === undefined) | |
| return; | |
| } | |
| name = name.toLowerCase(); | |
| if (params[name] === undefined) | |
| params[name] = value; | |
| } | |
| return params; | |
| } | |
| function getDecoder(charset) { | |
| let lc; | |
| while (true) { | |
| switch (charset) { | |
| case 'utf-8': | |
| case 'utf8': | |
| return decoders.utf8; | |
| case 'latin1': | |
| case 'ascii': // TODO: Make these a separate, strict decoder? | |
| case 'us-ascii': | |
| case 'iso-8859-1': | |
| case 'iso8859-1': | |
| case 'iso88591': | |
| case 'iso_8859-1': | |
| case 'windows-1252': | |
| case 'iso_8859-1:1987': | |
| case 'cp1252': | |
| case 'x-cp1252': | |
| return decoders.latin1; | |
| case 'utf16le': | |
| case 'utf-16le': | |
| case 'ucs2': | |
| case 'ucs-2': | |
| return decoders.utf16le; | |
| case 'base64': | |
| return decoders.base64; | |
| default: | |
| if (lc === undefined) { | |
| lc = true; | |
| charset = charset.toLowerCase(); | |
| continue; | |
| } | |
| return decoders.other.bind(charset); | |
| } | |
| } | |
| } | |
| const decoders = { | |
| utf8: (data, hint) => { | |
| if (data.length === 0) | |
| return ''; | |
| if (typeof data === 'string') { | |
| // If `data` never had any percent-encoded bytes or never had any that | |
| // were outside of the ASCII range, then we can safely just return the | |
| // input since UTF-8 is ASCII compatible | |
| if (hint < 2) | |
| return data; | |
| data = Buffer.from(data, 'latin1'); | |
| } | |
| return data.utf8Slice(0, data.length); | |
| }, | |
| latin1: (data, hint) => { | |
| if (data.length === 0) | |
| return ''; | |
| if (typeof data === 'string') | |
| return data; | |
| return data.latin1Slice(0, data.length); | |
| }, | |
| utf16le: (data, hint) => { | |
| if (data.length === 0) | |
| return ''; | |
| if (typeof data === 'string') | |
| data = Buffer.from(data, 'latin1'); | |
| return data.ucs2Slice(0, data.length); | |
| }, | |
| base64: (data, hint) => { | |
| if (data.length === 0) | |
| return ''; | |
| if (typeof data === 'string') | |
| data = Buffer.from(data, 'latin1'); | |
| return data.base64Slice(0, data.length); | |
| }, | |
| other: (data, hint) => { | |
| if (data.length === 0) | |
| return ''; | |
| if (typeof data === 'string') | |
| data = Buffer.from(data, 'latin1'); | |
| try { | |
| const decoder = new TextDecoder(this); | |
| return decoder.decode(data); | |
| } catch {} | |
| }, | |
| }; | |
| function convertToUTF8(data, charset, hint) { | |
| const decode = getDecoder(charset); | |
| if (decode) | |
| return decode(data, hint); | |
| } | |
| function basename(path) { | |
| if (typeof path !== 'string') | |
| return ''; | |
| for (let i = path.length - 1; i >= 0; --i) { | |
| switch (path.charCodeAt(i)) { | |
| case 0x2F: // '/' | |
| case 0x5C: // '\' | |
| path = path.slice(i + 1); | |
| return (path === '..' || path === '.' ? '' : path); | |
| } | |
| } | |
| return (path === '..' || path === '.' ? '' : path); | |
| } | |
| const TOKEN = [ | |
| 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, | |
| 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, | |
| 0, 1, 0, 1, 1, 1, 1, 1, 0, 0, 1, 1, 0, 1, 1, 0, | |
| 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, | |
| 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, | |
| 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 1, 1, | |
| 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, | |
| 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 0, 1, 0, | |
| 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, | |
| 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, | |
| 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, | |
| 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, | |
| 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, | |
| 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, | |
| 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, | |
| 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, | |
| ]; | |
| const QDTEXT = [ | |
| 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, | |
| 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, | |
| 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, | |
| 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, | |
| 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, | |
| 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, | |
| 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, | |
| 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, | |
| 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, | |
| 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, | |
| 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, | |
| 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, | |
| 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, | |
| 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, | |
| 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, | |
| 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, | |
| ]; | |
| const CHARSET = [ | |
| 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, | |
| 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, | |
| 0, 1, 0, 1, 1, 1, 1, 0, 0, 0, 0, 1, 0, 1, 0, 0, | |
| 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, | |
| 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, | |
| 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 1, 1, | |
| 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, | |
| 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 0, | |
| 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, | |
| 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, | |
| 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, | |
| 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, | |
| 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, | |
| 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, | |
| 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, | |
| 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, | |
| ]; | |
| const EXTENDED_VALUE = [ | |
| 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, | |
| 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, | |
| 0, 1, 0, 1, 1, 0, 1, 0, 0, 0, 0, 1, 0, 1, 1, 0, | |
| 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, | |
| 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, | |
| 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 1, 1, | |
| 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, | |
| 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 0, 1, 0, | |
| 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, | |
| 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, | |
| 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, | |
| 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, | |
| 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, | |
| 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, | |
| 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, | |
| 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, | |
| ]; | |
| /* eslint-disable no-multi-spaces */ | |
| const HEX_VALUES = [ | |
| -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, | |
| -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, | |
| -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, | |
| 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, -1, -1, -1, -1, -1, -1, | |
| -1, 10, 11, 12, 13, 14, 15, -1, -1, -1, -1, -1, -1, -1, -1, -1, | |
| -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, | |
| -1, 10, 11, 12, 13, 14, 15, -1, -1, -1, -1, -1, -1, -1, -1, -1, | |
| -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, | |
| -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, | |
| -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, | |
| -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, | |
| -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, | |
| -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, | |
| -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, | |
| -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, | |
| -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, | |
| ]; | |
| /* eslint-enable no-multi-spaces */ | |
| module.exports = { | |
| basename, | |
| convertToUTF8, | |
| getDecoder, | |
| parseContentType, | |
| parseDisposition, | |
| }; | |