123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596 |
- 'use strict';
- 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,
- };
|