1007 lines
32 KiB
JavaScript
1007 lines
32 KiB
JavaScript
|
'use strict';
|
||
|
// TODO: in core-js@4, move /modules/ dependencies to public entries for better optimization by tools like `preset-env`
|
||
|
require('../modules/es.string.iterator');
|
||
|
var $ = require('../internals/export');
|
||
|
var DESCRIPTORS = require('../internals/descriptors');
|
||
|
var USE_NATIVE_URL = require('../internals/native-url');
|
||
|
var global = require('../internals/global');
|
||
|
var defineProperties = require('../internals/object-define-properties');
|
||
|
var redefine = require('../internals/redefine');
|
||
|
var anInstance = require('../internals/an-instance');
|
||
|
var has = require('../internals/has');
|
||
|
var assign = require('../internals/object-assign');
|
||
|
var arrayFrom = require('../internals/array-from');
|
||
|
var codeAt = require('../internals/string-multibyte').codeAt;
|
||
|
var toASCII = require('../internals/string-punycode-to-ascii');
|
||
|
var setToStringTag = require('../internals/set-to-string-tag');
|
||
|
var URLSearchParamsModule = require('../modules/web.url-search-params');
|
||
|
var InternalStateModule = require('../internals/internal-state');
|
||
|
|
||
|
var NativeURL = global.URL;
|
||
|
var URLSearchParams = URLSearchParamsModule.URLSearchParams;
|
||
|
var getInternalSearchParamsState = URLSearchParamsModule.getState;
|
||
|
var setInternalState = InternalStateModule.set;
|
||
|
var getInternalURLState = InternalStateModule.getterFor('URL');
|
||
|
var floor = Math.floor;
|
||
|
var pow = Math.pow;
|
||
|
|
||
|
var INVALID_AUTHORITY = 'Invalid authority';
|
||
|
var INVALID_SCHEME = 'Invalid scheme';
|
||
|
var INVALID_HOST = 'Invalid host';
|
||
|
var INVALID_PORT = 'Invalid port';
|
||
|
|
||
|
var ALPHA = /[A-Za-z]/;
|
||
|
// eslint-disable-next-line regexp/no-obscure-range -- safe
|
||
|
var ALPHANUMERIC = /[\d+-.A-Za-z]/;
|
||
|
var DIGIT = /\d/;
|
||
|
var HEX_START = /^0x/i;
|
||
|
var OCT = /^[0-7]+$/;
|
||
|
var DEC = /^\d+$/;
|
||
|
var HEX = /^[\dA-Fa-f]+$/;
|
||
|
/* eslint-disable no-control-regex -- safe */
|
||
|
var FORBIDDEN_HOST_CODE_POINT = /[\0\t\n\r #%/:<>?@[\\\]^|]/;
|
||
|
var FORBIDDEN_HOST_CODE_POINT_EXCLUDING_PERCENT = /[\0\t\n\r #/:<>?@[\\\]^|]/;
|
||
|
var LEADING_AND_TRAILING_C0_CONTROL_OR_SPACE = /^[\u0000-\u001F ]+|[\u0000-\u001F ]+$/g;
|
||
|
var TAB_AND_NEW_LINE = /[\t\n\r]/g;
|
||
|
/* eslint-enable no-control-regex -- safe */
|
||
|
var EOF;
|
||
|
|
||
|
var parseHost = function (url, input) {
|
||
|
var result, codePoints, index;
|
||
|
if (input.charAt(0) == '[') {
|
||
|
if (input.charAt(input.length - 1) != ']') return INVALID_HOST;
|
||
|
result = parseIPv6(input.slice(1, -1));
|
||
|
if (!result) return INVALID_HOST;
|
||
|
url.host = result;
|
||
|
// opaque host
|
||
|
} else if (!isSpecial(url)) {
|
||
|
if (FORBIDDEN_HOST_CODE_POINT_EXCLUDING_PERCENT.test(input)) return INVALID_HOST;
|
||
|
result = '';
|
||
|
codePoints = arrayFrom(input);
|
||
|
for (index = 0; index < codePoints.length; index++) {
|
||
|
result += percentEncode(codePoints[index], C0ControlPercentEncodeSet);
|
||
|
}
|
||
|
url.host = result;
|
||
|
} else {
|
||
|
input = toASCII(input);
|
||
|
if (FORBIDDEN_HOST_CODE_POINT.test(input)) return INVALID_HOST;
|
||
|
result = parseIPv4(input);
|
||
|
if (result === null) return INVALID_HOST;
|
||
|
url.host = result;
|
||
|
}
|
||
|
};
|
||
|
|
||
|
var parseIPv4 = function (input) {
|
||
|
var parts = input.split('.');
|
||
|
var partsLength, numbers, index, part, radix, number, ipv4;
|
||
|
if (parts.length && parts[parts.length - 1] == '') {
|
||
|
parts.pop();
|
||
|
}
|
||
|
partsLength = parts.length;
|
||
|
if (partsLength > 4) return input;
|
||
|
numbers = [];
|
||
|
for (index = 0; index < partsLength; index++) {
|
||
|
part = parts[index];
|
||
|
if (part == '') return input;
|
||
|
radix = 10;
|
||
|
if (part.length > 1 && part.charAt(0) == '0') {
|
||
|
radix = HEX_START.test(part) ? 16 : 8;
|
||
|
part = part.slice(radix == 8 ? 1 : 2);
|
||
|
}
|
||
|
if (part === '') {
|
||
|
number = 0;
|
||
|
} else {
|
||
|
if (!(radix == 10 ? DEC : radix == 8 ? OCT : HEX).test(part)) return input;
|
||
|
number = parseInt(part, radix);
|
||
|
}
|
||
|
numbers.push(number);
|
||
|
}
|
||
|
for (index = 0; index < partsLength; index++) {
|
||
|
number = numbers[index];
|
||
|
if (index == partsLength - 1) {
|
||
|
if (number >= pow(256, 5 - partsLength)) return null;
|
||
|
} else if (number > 255) return null;
|
||
|
}
|
||
|
ipv4 = numbers.pop();
|
||
|
for (index = 0; index < numbers.length; index++) {
|
||
|
ipv4 += numbers[index] * pow(256, 3 - index);
|
||
|
}
|
||
|
return ipv4;
|
||
|
};
|
||
|
|
||
|
// eslint-disable-next-line max-statements -- TODO
|
||
|
var parseIPv6 = function (input) {
|
||
|
var address = [0, 0, 0, 0, 0, 0, 0, 0];
|
||
|
var pieceIndex = 0;
|
||
|
var compress = null;
|
||
|
var pointer = 0;
|
||
|
var value, length, numbersSeen, ipv4Piece, number, swaps, swap;
|
||
|
|
||
|
var char = function () {
|
||
|
return input.charAt(pointer);
|
||
|
};
|
||
|
|
||
|
if (char() == ':') {
|
||
|
if (input.charAt(1) != ':') return;
|
||
|
pointer += 2;
|
||
|
pieceIndex++;
|
||
|
compress = pieceIndex;
|
||
|
}
|
||
|
while (char()) {
|
||
|
if (pieceIndex == 8) return;
|
||
|
if (char() == ':') {
|
||
|
if (compress !== null) return;
|
||
|
pointer++;
|
||
|
pieceIndex++;
|
||
|
compress = pieceIndex;
|
||
|
continue;
|
||
|
}
|
||
|
value = length = 0;
|
||
|
while (length < 4 && HEX.test(char())) {
|
||
|
value = value * 16 + parseInt(char(), 16);
|
||
|
pointer++;
|
||
|
length++;
|
||
|
}
|
||
|
if (char() == '.') {
|
||
|
if (length == 0) return;
|
||
|
pointer -= length;
|
||
|
if (pieceIndex > 6) return;
|
||
|
numbersSeen = 0;
|
||
|
while (char()) {
|
||
|
ipv4Piece = null;
|
||
|
if (numbersSeen > 0) {
|
||
|
if (char() == '.' && numbersSeen < 4) pointer++;
|
||
|
else return;
|
||
|
}
|
||
|
if (!DIGIT.test(char())) return;
|
||
|
while (DIGIT.test(char())) {
|
||
|
number = parseInt(char(), 10);
|
||
|
if (ipv4Piece === null) ipv4Piece = number;
|
||
|
else if (ipv4Piece == 0) return;
|
||
|
else ipv4Piece = ipv4Piece * 10 + number;
|
||
|
if (ipv4Piece > 255) return;
|
||
|
pointer++;
|
||
|
}
|
||
|
address[pieceIndex] = address[pieceIndex] * 256 + ipv4Piece;
|
||
|
numbersSeen++;
|
||
|
if (numbersSeen == 2 || numbersSeen == 4) pieceIndex++;
|
||
|
}
|
||
|
if (numbersSeen != 4) return;
|
||
|
break;
|
||
|
} else if (char() == ':') {
|
||
|
pointer++;
|
||
|
if (!char()) return;
|
||
|
} else if (char()) return;
|
||
|
address[pieceIndex++] = value;
|
||
|
}
|
||
|
if (compress !== null) {
|
||
|
swaps = pieceIndex - compress;
|
||
|
pieceIndex = 7;
|
||
|
while (pieceIndex != 0 && swaps > 0) {
|
||
|
swap = address[pieceIndex];
|
||
|
address[pieceIndex--] = address[compress + swaps - 1];
|
||
|
address[compress + --swaps] = swap;
|
||
|
}
|
||
|
} else if (pieceIndex != 8) return;
|
||
|
return address;
|
||
|
};
|
||
|
|
||
|
var findLongestZeroSequence = function (ipv6) {
|
||
|
var maxIndex = null;
|
||
|
var maxLength = 1;
|
||
|
var currStart = null;
|
||
|
var currLength = 0;
|
||
|
var index = 0;
|
||
|
for (; index < 8; index++) {
|
||
|
if (ipv6[index] !== 0) {
|
||
|
if (currLength > maxLength) {
|
||
|
maxIndex = currStart;
|
||
|
maxLength = currLength;
|
||
|
}
|
||
|
currStart = null;
|
||
|
currLength = 0;
|
||
|
} else {
|
||
|
if (currStart === null) currStart = index;
|
||
|
++currLength;
|
||
|
}
|
||
|
}
|
||
|
if (currLength > maxLength) {
|
||
|
maxIndex = currStart;
|
||
|
maxLength = currLength;
|
||
|
}
|
||
|
return maxIndex;
|
||
|
};
|
||
|
|
||
|
var serializeHost = function (host) {
|
||
|
var result, index, compress, ignore0;
|
||
|
// ipv4
|
||
|
if (typeof host == 'number') {
|
||
|
result = [];
|
||
|
for (index = 0; index < 4; index++) {
|
||
|
result.unshift(host % 256);
|
||
|
host = floor(host / 256);
|
||
|
} return result.join('.');
|
||
|
// ipv6
|
||
|
} else if (typeof host == 'object') {
|
||
|
result = '';
|
||
|
compress = findLongestZeroSequence(host);
|
||
|
for (index = 0; index < 8; index++) {
|
||
|
if (ignore0 && host[index] === 0) continue;
|
||
|
if (ignore0) ignore0 = false;
|
||
|
if (compress === index) {
|
||
|
result += index ? ':' : '::';
|
||
|
ignore0 = true;
|
||
|
} else {
|
||
|
result += host[index].toString(16);
|
||
|
if (index < 7) result += ':';
|
||
|
}
|
||
|
}
|
||
|
return '[' + result + ']';
|
||
|
} return host;
|
||
|
};
|
||
|
|
||
|
var C0ControlPercentEncodeSet = {};
|
||
|
var fragmentPercentEncodeSet = assign({}, C0ControlPercentEncodeSet, {
|
||
|
' ': 1, '"': 1, '<': 1, '>': 1, '`': 1
|
||
|
});
|
||
|
var pathPercentEncodeSet = assign({}, fragmentPercentEncodeSet, {
|
||
|
'#': 1, '?': 1, '{': 1, '}': 1
|
||
|
});
|
||
|
var userinfoPercentEncodeSet = assign({}, pathPercentEncodeSet, {
|
||
|
'/': 1, ':': 1, ';': 1, '=': 1, '@': 1, '[': 1, '\\': 1, ']': 1, '^': 1, '|': 1
|
||
|
});
|
||
|
|
||
|
var percentEncode = function (char, set) {
|
||
|
var code = codeAt(char, 0);
|
||
|
return code > 0x20 && code < 0x7F && !has(set, char) ? char : encodeURIComponent(char);
|
||
|
};
|
||
|
|
||
|
var specialSchemes = {
|
||
|
ftp: 21,
|
||
|
file: null,
|
||
|
http: 80,
|
||
|
https: 443,
|
||
|
ws: 80,
|
||
|
wss: 443
|
||
|
};
|
||
|
|
||
|
var isSpecial = function (url) {
|
||
|
return has(specialSchemes, url.scheme);
|
||
|
};
|
||
|
|
||
|
var includesCredentials = function (url) {
|
||
|
return url.username != '' || url.password != '';
|
||
|
};
|
||
|
|
||
|
var cannotHaveUsernamePasswordPort = function (url) {
|
||
|
return !url.host || url.cannotBeABaseURL || url.scheme == 'file';
|
||
|
};
|
||
|
|
||
|
var isWindowsDriveLetter = function (string, normalized) {
|
||
|
var second;
|
||
|
return string.length == 2 && ALPHA.test(string.charAt(0))
|
||
|
&& ((second = string.charAt(1)) == ':' || (!normalized && second == '|'));
|
||
|
};
|
||
|
|
||
|
var startsWithWindowsDriveLetter = function (string) {
|
||
|
var third;
|
||
|
return string.length > 1 && isWindowsDriveLetter(string.slice(0, 2)) && (
|
||
|
string.length == 2 ||
|
||
|
((third = string.charAt(2)) === '/' || third === '\\' || third === '?' || third === '#')
|
||
|
);
|
||
|
};
|
||
|
|
||
|
var shortenURLsPath = function (url) {
|
||
|
var path = url.path;
|
||
|
var pathSize = path.length;
|
||
|
if (pathSize && (url.scheme != 'file' || pathSize != 1 || !isWindowsDriveLetter(path[0], true))) {
|
||
|
path.pop();
|
||
|
}
|
||
|
};
|
||
|
|
||
|
var isSingleDot = function (segment) {
|
||
|
return segment === '.' || segment.toLowerCase() === '%2e';
|
||
|
};
|
||
|
|
||
|
var isDoubleDot = function (segment) {
|
||
|
segment = segment.toLowerCase();
|
||
|
return segment === '..' || segment === '%2e.' || segment === '.%2e' || segment === '%2e%2e';
|
||
|
};
|
||
|
|
||
|
// States:
|
||
|
var SCHEME_START = {};
|
||
|
var SCHEME = {};
|
||
|
var NO_SCHEME = {};
|
||
|
var SPECIAL_RELATIVE_OR_AUTHORITY = {};
|
||
|
var PATH_OR_AUTHORITY = {};
|
||
|
var RELATIVE = {};
|
||
|
var RELATIVE_SLASH = {};
|
||
|
var SPECIAL_AUTHORITY_SLASHES = {};
|
||
|
var SPECIAL_AUTHORITY_IGNORE_SLASHES = {};
|
||
|
var AUTHORITY = {};
|
||
|
var HOST = {};
|
||
|
var HOSTNAME = {};
|
||
|
var PORT = {};
|
||
|
var FILE = {};
|
||
|
var FILE_SLASH = {};
|
||
|
var FILE_HOST = {};
|
||
|
var PATH_START = {};
|
||
|
var PATH = {};
|
||
|
var CANNOT_BE_A_BASE_URL_PATH = {};
|
||
|
var QUERY = {};
|
||
|
var FRAGMENT = {};
|
||
|
|
||
|
// eslint-disable-next-line max-statements -- TODO
|
||
|
var parseURL = function (url, input, stateOverride, base) {
|
||
|
var state = stateOverride || SCHEME_START;
|
||
|
var pointer = 0;
|
||
|
var buffer = '';
|
||
|
var seenAt = false;
|
||
|
var seenBracket = false;
|
||
|
var seenPasswordToken = false;
|
||
|
var codePoints, char, bufferCodePoints, failure;
|
||
|
|
||
|
if (!stateOverride) {
|
||
|
url.scheme = '';
|
||
|
url.username = '';
|
||
|
url.password = '';
|
||
|
url.host = null;
|
||
|
url.port = null;
|
||
|
url.path = [];
|
||
|
url.query = null;
|
||
|
url.fragment = null;
|
||
|
url.cannotBeABaseURL = false;
|
||
|
input = input.replace(LEADING_AND_TRAILING_C0_CONTROL_OR_SPACE, '');
|
||
|
}
|
||
|
|
||
|
input = input.replace(TAB_AND_NEW_LINE, '');
|
||
|
|
||
|
codePoints = arrayFrom(input);
|
||
|
|
||
|
while (pointer <= codePoints.length) {
|
||
|
char = codePoints[pointer];
|
||
|
switch (state) {
|
||
|
case SCHEME_START:
|
||
|
if (char && ALPHA.test(char)) {
|
||
|
buffer += char.toLowerCase();
|
||
|
state = SCHEME;
|
||
|
} else if (!stateOverride) {
|
||
|
state = NO_SCHEME;
|
||
|
continue;
|
||
|
} else return INVALID_SCHEME;
|
||
|
break;
|
||
|
|
||
|
case SCHEME:
|
||
|
if (char && (ALPHANUMERIC.test(char) || char == '+' || char == '-' || char == '.')) {
|
||
|
buffer += char.toLowerCase();
|
||
|
} else if (char == ':') {
|
||
|
if (stateOverride && (
|
||
|
(isSpecial(url) != has(specialSchemes, buffer)) ||
|
||
|
(buffer == 'file' && (includesCredentials(url) || url.port !== null)) ||
|
||
|
(url.scheme == 'file' && !url.host)
|
||
|
)) return;
|
||
|
url.scheme = buffer;
|
||
|
if (stateOverride) {
|
||
|
if (isSpecial(url) && specialSchemes[url.scheme] == url.port) url.port = null;
|
||
|
return;
|
||
|
}
|
||
|
buffer = '';
|
||
|
if (url.scheme == 'file') {
|
||
|
state = FILE;
|
||
|
} else if (isSpecial(url) && base && base.scheme == url.scheme) {
|
||
|
state = SPECIAL_RELATIVE_OR_AUTHORITY;
|
||
|
} else if (isSpecial(url)) {
|
||
|
state = SPECIAL_AUTHORITY_SLASHES;
|
||
|
} else if (codePoints[pointer + 1] == '/') {
|
||
|
state = PATH_OR_AUTHORITY;
|
||
|
pointer++;
|
||
|
} else {
|
||
|
url.cannotBeABaseURL = true;
|
||
|
url.path.push('');
|
||
|
state = CANNOT_BE_A_BASE_URL_PATH;
|
||
|
}
|
||
|
} else if (!stateOverride) {
|
||
|
buffer = '';
|
||
|
state = NO_SCHEME;
|
||
|
pointer = 0;
|
||
|
continue;
|
||
|
} else return INVALID_SCHEME;
|
||
|
break;
|
||
|
|
||
|
case NO_SCHEME:
|
||
|
if (!base || (base.cannotBeABaseURL && char != '#')) return INVALID_SCHEME;
|
||
|
if (base.cannotBeABaseURL && char == '#') {
|
||
|
url.scheme = base.scheme;
|
||
|
url.path = base.path.slice();
|
||
|
url.query = base.query;
|
||
|
url.fragment = '';
|
||
|
url.cannotBeABaseURL = true;
|
||
|
state = FRAGMENT;
|
||
|
break;
|
||
|
}
|
||
|
state = base.scheme == 'file' ? FILE : RELATIVE;
|
||
|
continue;
|
||
|
|
||
|
case SPECIAL_RELATIVE_OR_AUTHORITY:
|
||
|
if (char == '/' && codePoints[pointer + 1] == '/') {
|
||
|
state = SPECIAL_AUTHORITY_IGNORE_SLASHES;
|
||
|
pointer++;
|
||
|
} else {
|
||
|
state = RELATIVE;
|
||
|
continue;
|
||
|
} break;
|
||
|
|
||
|
case PATH_OR_AUTHORITY:
|
||
|
if (char == '/') {
|
||
|
state = AUTHORITY;
|
||
|
break;
|
||
|
} else {
|
||
|
state = PATH;
|
||
|
continue;
|
||
|
}
|
||
|
|
||
|
case RELATIVE:
|
||
|
url.scheme = base.scheme;
|
||
|
if (char == EOF) {
|
||
|
url.username = base.username;
|
||
|
url.password = base.password;
|
||
|
url.host = base.host;
|
||
|
url.port = base.port;
|
||
|
url.path = base.path.slice();
|
||
|
url.query = base.query;
|
||
|
} else if (char == '/' || (char == '\\' && isSpecial(url))) {
|
||
|
state = RELATIVE_SLASH;
|
||
|
} else if (char == '?') {
|
||
|
url.username = base.username;
|
||
|
url.password = base.password;
|
||
|
url.host = base.host;
|
||
|
url.port = base.port;
|
||
|
url.path = base.path.slice();
|
||
|
url.query = '';
|
||
|
state = QUERY;
|
||
|
} else if (char == '#') {
|
||
|
url.username = base.username;
|
||
|
url.password = base.password;
|
||
|
url.host = base.host;
|
||
|
url.port = base.port;
|
||
|
url.path = base.path.slice();
|
||
|
url.query = base.query;
|
||
|
url.fragment = '';
|
||
|
state = FRAGMENT;
|
||
|
} else {
|
||
|
url.username = base.username;
|
||
|
url.password = base.password;
|
||
|
url.host = base.host;
|
||
|
url.port = base.port;
|
||
|
url.path = base.path.slice();
|
||
|
url.path.pop();
|
||
|
state = PATH;
|
||
|
continue;
|
||
|
} break;
|
||
|
|
||
|
case RELATIVE_SLASH:
|
||
|
if (isSpecial(url) && (char == '/' || char == '\\')) {
|
||
|
state = SPECIAL_AUTHORITY_IGNORE_SLASHES;
|
||
|
} else if (char == '/') {
|
||
|
state = AUTHORITY;
|
||
|
} else {
|
||
|
url.username = base.username;
|
||
|
url.password = base.password;
|
||
|
url.host = base.host;
|
||
|
url.port = base.port;
|
||
|
state = PATH;
|
||
|
continue;
|
||
|
} break;
|
||
|
|
||
|
case SPECIAL_AUTHORITY_SLASHES:
|
||
|
state = SPECIAL_AUTHORITY_IGNORE_SLASHES;
|
||
|
if (char != '/' || buffer.charAt(pointer + 1) != '/') continue;
|
||
|
pointer++;
|
||
|
break;
|
||
|
|
||
|
case SPECIAL_AUTHORITY_IGNORE_SLASHES:
|
||
|
if (char != '/' && char != '\\') {
|
||
|
state = AUTHORITY;
|
||
|
continue;
|
||
|
} break;
|
||
|
|
||
|
case AUTHORITY:
|
||
|
if (char == '@') {
|
||
|
if (seenAt) buffer = '%40' + buffer;
|
||
|
seenAt = true;
|
||
|
bufferCodePoints = arrayFrom(buffer);
|
||
|
for (var i = 0; i < bufferCodePoints.length; i++) {
|
||
|
var codePoint = bufferCodePoints[i];
|
||
|
if (codePoint == ':' && !seenPasswordToken) {
|
||
|
seenPasswordToken = true;
|
||
|
continue;
|
||
|
}
|
||
|
var encodedCodePoints = percentEncode(codePoint, userinfoPercentEncodeSet);
|
||
|
if (seenPasswordToken) url.password += encodedCodePoints;
|
||
|
else url.username += encodedCodePoints;
|
||
|
}
|
||
|
buffer = '';
|
||
|
} else if (
|
||
|
char == EOF || char == '/' || char == '?' || char == '#' ||
|
||
|
(char == '\\' && isSpecial(url))
|
||
|
) {
|
||
|
if (seenAt && buffer == '') return INVALID_AUTHORITY;
|
||
|
pointer -= arrayFrom(buffer).length + 1;
|
||
|
buffer = '';
|
||
|
state = HOST;
|
||
|
} else buffer += char;
|
||
|
break;
|
||
|
|
||
|
case HOST:
|
||
|
case HOSTNAME:
|
||
|
if (stateOverride && url.scheme == 'file') {
|
||
|
state = FILE_HOST;
|
||
|
continue;
|
||
|
} else if (char == ':' && !seenBracket) {
|
||
|
if (buffer == '') return INVALID_HOST;
|
||
|
failure = parseHost(url, buffer);
|
||
|
if (failure) return failure;
|
||
|
buffer = '';
|
||
|
state = PORT;
|
||
|
if (stateOverride == HOSTNAME) return;
|
||
|
} else if (
|
||
|
char == EOF || char == '/' || char == '?' || char == '#' ||
|
||
|
(char == '\\' && isSpecial(url))
|
||
|
) {
|
||
|
if (isSpecial(url) && buffer == '') return INVALID_HOST;
|
||
|
if (stateOverride && buffer == '' && (includesCredentials(url) || url.port !== null)) return;
|
||
|
failure = parseHost(url, buffer);
|
||
|
if (failure) return failure;
|
||
|
buffer = '';
|
||
|
state = PATH_START;
|
||
|
if (stateOverride) return;
|
||
|
continue;
|
||
|
} else {
|
||
|
if (char == '[') seenBracket = true;
|
||
|
else if (char == ']') seenBracket = false;
|
||
|
buffer += char;
|
||
|
} break;
|
||
|
|
||
|
case PORT:
|
||
|
if (DIGIT.test(char)) {
|
||
|
buffer += char;
|
||
|
} else if (
|
||
|
char == EOF || char == '/' || char == '?' || char == '#' ||
|
||
|
(char == '\\' && isSpecial(url)) ||
|
||
|
stateOverride
|
||
|
) {
|
||
|
if (buffer != '') {
|
||
|
var port = parseInt(buffer, 10);
|
||
|
if (port > 0xFFFF) return INVALID_PORT;
|
||
|
url.port = (isSpecial(url) && port === specialSchemes[url.scheme]) ? null : port;
|
||
|
buffer = '';
|
||
|
}
|
||
|
if (stateOverride) return;
|
||
|
state = PATH_START;
|
||
|
continue;
|
||
|
} else return INVALID_PORT;
|
||
|
break;
|
||
|
|
||
|
case FILE:
|
||
|
url.scheme = 'file';
|
||
|
if (char == '/' || char == '\\') state = FILE_SLASH;
|
||
|
else if (base && base.scheme == 'file') {
|
||
|
if (char == EOF) {
|
||
|
url.host = base.host;
|
||
|
url.path = base.path.slice();
|
||
|
url.query = base.query;
|
||
|
} else if (char == '?') {
|
||
|
url.host = base.host;
|
||
|
url.path = base.path.slice();
|
||
|
url.query = '';
|
||
|
state = QUERY;
|
||
|
} else if (char == '#') {
|
||
|
url.host = base.host;
|
||
|
url.path = base.path.slice();
|
||
|
url.query = base.query;
|
||
|
url.fragment = '';
|
||
|
state = FRAGMENT;
|
||
|
} else {
|
||
|
if (!startsWithWindowsDriveLetter(codePoints.slice(pointer).join(''))) {
|
||
|
url.host = base.host;
|
||
|
url.path = base.path.slice();
|
||
|
shortenURLsPath(url);
|
||
|
}
|
||
|
state = PATH;
|
||
|
continue;
|
||
|
}
|
||
|
} else {
|
||
|
state = PATH;
|
||
|
continue;
|
||
|
} break;
|
||
|
|
||
|
case FILE_SLASH:
|
||
|
if (char == '/' || char == '\\') {
|
||
|
state = FILE_HOST;
|
||
|
break;
|
||
|
}
|
||
|
if (base && base.scheme == 'file' && !startsWithWindowsDriveLetter(codePoints.slice(pointer).join(''))) {
|
||
|
if (isWindowsDriveLetter(base.path[0], true)) url.path.push(base.path[0]);
|
||
|
else url.host = base.host;
|
||
|
}
|
||
|
state = PATH;
|
||
|
continue;
|
||
|
|
||
|
case FILE_HOST:
|
||
|
if (char == EOF || char == '/' || char == '\\' || char == '?' || char == '#') {
|
||
|
if (!stateOverride && isWindowsDriveLetter(buffer)) {
|
||
|
state = PATH;
|
||
|
} else if (buffer == '') {
|
||
|
url.host = '';
|
||
|
if (stateOverride) return;
|
||
|
state = PATH_START;
|
||
|
} else {
|
||
|
failure = parseHost(url, buffer);
|
||
|
if (failure) return failure;
|
||
|
if (url.host == 'localhost') url.host = '';
|
||
|
if (stateOverride) return;
|
||
|
buffer = '';
|
||
|
state = PATH_START;
|
||
|
} continue;
|
||
|
} else buffer += char;
|
||
|
break;
|
||
|
|
||
|
case PATH_START:
|
||
|
if (isSpecial(url)) {
|
||
|
state = PATH;
|
||
|
if (char != '/' && char != '\\') continue;
|
||
|
} else if (!stateOverride && char == '?') {
|
||
|
url.query = '';
|
||
|
state = QUERY;
|
||
|
} else if (!stateOverride && char == '#') {
|
||
|
url.fragment = '';
|
||
|
state = FRAGMENT;
|
||
|
} else if (char != EOF) {
|
||
|
state = PATH;
|
||
|
if (char != '/') continue;
|
||
|
} break;
|
||
|
|
||
|
case PATH:
|
||
|
if (
|
||
|
char == EOF || char == '/' ||
|
||
|
(char == '\\' && isSpecial(url)) ||
|
||
|
(!stateOverride && (char == '?' || char == '#'))
|
||
|
) {
|
||
|
if (isDoubleDot(buffer)) {
|
||
|
shortenURLsPath(url);
|
||
|
if (char != '/' && !(char == '\\' && isSpecial(url))) {
|
||
|
url.path.push('');
|
||
|
}
|
||
|
} else if (isSingleDot(buffer)) {
|
||
|
if (char != '/' && !(char == '\\' && isSpecial(url))) {
|
||
|
url.path.push('');
|
||
|
}
|
||
|
} else {
|
||
|
if (url.scheme == 'file' && !url.path.length && isWindowsDriveLetter(buffer)) {
|
||
|
if (url.host) url.host = '';
|
||
|
buffer = buffer.charAt(0) + ':'; // normalize windows drive letter
|
||
|
}
|
||
|
url.path.push(buffer);
|
||
|
}
|
||
|
buffer = '';
|
||
|
if (url.scheme == 'file' && (char == EOF || char == '?' || char == '#')) {
|
||
|
while (url.path.length > 1 && url.path[0] === '') {
|
||
|
url.path.shift();
|
||
|
}
|
||
|
}
|
||
|
if (char == '?') {
|
||
|
url.query = '';
|
||
|
state = QUERY;
|
||
|
} else if (char == '#') {
|
||
|
url.fragment = '';
|
||
|
state = FRAGMENT;
|
||
|
}
|
||
|
} else {
|
||
|
buffer += percentEncode(char, pathPercentEncodeSet);
|
||
|
} break;
|
||
|
|
||
|
case CANNOT_BE_A_BASE_URL_PATH:
|
||
|
if (char == '?') {
|
||
|
url.query = '';
|
||
|
state = QUERY;
|
||
|
} else if (char == '#') {
|
||
|
url.fragment = '';
|
||
|
state = FRAGMENT;
|
||
|
} else if (char != EOF) {
|
||
|
url.path[0] += percentEncode(char, C0ControlPercentEncodeSet);
|
||
|
} break;
|
||
|
|
||
|
case QUERY:
|
||
|
if (!stateOverride && char == '#') {
|
||
|
url.fragment = '';
|
||
|
state = FRAGMENT;
|
||
|
} else if (char != EOF) {
|
||
|
if (char == "'" && isSpecial(url)) url.query += '%27';
|
||
|
else if (char == '#') url.query += '%23';
|
||
|
else url.query += percentEncode(char, C0ControlPercentEncodeSet);
|
||
|
} break;
|
||
|
|
||
|
case FRAGMENT:
|
||
|
if (char != EOF) url.fragment += percentEncode(char, fragmentPercentEncodeSet);
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
pointer++;
|
||
|
}
|
||
|
};
|
||
|
|
||
|
// `URL` constructor
|
||
|
// https://url.spec.whatwg.org/#url-class
|
||
|
var URLConstructor = function URL(url /* , base */) {
|
||
|
var that = anInstance(this, URLConstructor, 'URL');
|
||
|
var base = arguments.length > 1 ? arguments[1] : undefined;
|
||
|
var urlString = String(url);
|
||
|
var state = setInternalState(that, { type: 'URL' });
|
||
|
var baseState, failure;
|
||
|
if (base !== undefined) {
|
||
|
if (base instanceof URLConstructor) baseState = getInternalURLState(base);
|
||
|
else {
|
||
|
failure = parseURL(baseState = {}, String(base));
|
||
|
if (failure) throw TypeError(failure);
|
||
|
}
|
||
|
}
|
||
|
failure = parseURL(state, urlString, null, baseState);
|
||
|
if (failure) throw TypeError(failure);
|
||
|
var searchParams = state.searchParams = new URLSearchParams();
|
||
|
var searchParamsState = getInternalSearchParamsState(searchParams);
|
||
|
searchParamsState.updateSearchParams(state.query);
|
||
|
searchParamsState.updateURL = function () {
|
||
|
state.query = String(searchParams) || null;
|
||
|
};
|
||
|
if (!DESCRIPTORS) {
|
||
|
that.href = serializeURL.call(that);
|
||
|
that.origin = getOrigin.call(that);
|
||
|
that.protocol = getProtocol.call(that);
|
||
|
that.username = getUsername.call(that);
|
||
|
that.password = getPassword.call(that);
|
||
|
that.host = getHost.call(that);
|
||
|
that.hostname = getHostname.call(that);
|
||
|
that.port = getPort.call(that);
|
||
|
that.pathname = getPathname.call(that);
|
||
|
that.search = getSearch.call(that);
|
||
|
that.searchParams = getSearchParams.call(that);
|
||
|
that.hash = getHash.call(that);
|
||
|
}
|
||
|
};
|
||
|
|
||
|
var URLPrototype = URLConstructor.prototype;
|
||
|
|
||
|
var serializeURL = function () {
|
||
|
var url = getInternalURLState(this);
|
||
|
var scheme = url.scheme;
|
||
|
var username = url.username;
|
||
|
var password = url.password;
|
||
|
var host = url.host;
|
||
|
var port = url.port;
|
||
|
var path = url.path;
|
||
|
var query = url.query;
|
||
|
var fragment = url.fragment;
|
||
|
var output = scheme + ':';
|
||
|
if (host !== null) {
|
||
|
output += '//';
|
||
|
if (includesCredentials(url)) {
|
||
|
output += username + (password ? ':' + password : '') + '@';
|
||
|
}
|
||
|
output += serializeHost(host);
|
||
|
if (port !== null) output += ':' + port;
|
||
|
} else if (scheme == 'file') output += '//';
|
||
|
output += url.cannotBeABaseURL ? path[0] : path.length ? '/' + path.join('/') : '';
|
||
|
if (query !== null) output += '?' + query;
|
||
|
if (fragment !== null) output += '#' + fragment;
|
||
|
return output;
|
||
|
};
|
||
|
|
||
|
var getOrigin = function () {
|
||
|
var url = getInternalURLState(this);
|
||
|
var scheme = url.scheme;
|
||
|
var port = url.port;
|
||
|
if (scheme == 'blob') try {
|
||
|
return new URLConstructor(scheme.path[0]).origin;
|
||
|
} catch (error) {
|
||
|
return 'null';
|
||
|
}
|
||
|
if (scheme == 'file' || !isSpecial(url)) return 'null';
|
||
|
return scheme + '://' + serializeHost(url.host) + (port !== null ? ':' + port : '');
|
||
|
};
|
||
|
|
||
|
var getProtocol = function () {
|
||
|
return getInternalURLState(this).scheme + ':';
|
||
|
};
|
||
|
|
||
|
var getUsername = function () {
|
||
|
return getInternalURLState(this).username;
|
||
|
};
|
||
|
|
||
|
var getPassword = function () {
|
||
|
return getInternalURLState(this).password;
|
||
|
};
|
||
|
|
||
|
var getHost = function () {
|
||
|
var url = getInternalURLState(this);
|
||
|
var host = url.host;
|
||
|
var port = url.port;
|
||
|
return host === null ? ''
|
||
|
: port === null ? serializeHost(host)
|
||
|
: serializeHost(host) + ':' + port;
|
||
|
};
|
||
|
|
||
|
var getHostname = function () {
|
||
|
var host = getInternalURLState(this).host;
|
||
|
return host === null ? '' : serializeHost(host);
|
||
|
};
|
||
|
|
||
|
var getPort = function () {
|
||
|
var port = getInternalURLState(this).port;
|
||
|
return port === null ? '' : String(port);
|
||
|
};
|
||
|
|
||
|
var getPathname = function () {
|
||
|
var url = getInternalURLState(this);
|
||
|
var path = url.path;
|
||
|
return url.cannotBeABaseURL ? path[0] : path.length ? '/' + path.join('/') : '';
|
||
|
};
|
||
|
|
||
|
var getSearch = function () {
|
||
|
var query = getInternalURLState(this).query;
|
||
|
return query ? '?' + query : '';
|
||
|
};
|
||
|
|
||
|
var getSearchParams = function () {
|
||
|
return getInternalURLState(this).searchParams;
|
||
|
};
|
||
|
|
||
|
var getHash = function () {
|
||
|
var fragment = getInternalURLState(this).fragment;
|
||
|
return fragment ? '#' + fragment : '';
|
||
|
};
|
||
|
|
||
|
var accessorDescriptor = function (getter, setter) {
|
||
|
return { get: getter, set: setter, configurable: true, enumerable: true };
|
||
|
};
|
||
|
|
||
|
if (DESCRIPTORS) {
|
||
|
defineProperties(URLPrototype, {
|
||
|
// `URL.prototype.href` accessors pair
|
||
|
// https://url.spec.whatwg.org/#dom-url-href
|
||
|
href: accessorDescriptor(serializeURL, function (href) {
|
||
|
var url = getInternalURLState(this);
|
||
|
var urlString = String(href);
|
||
|
var failure = parseURL(url, urlString);
|
||
|
if (failure) throw TypeError(failure);
|
||
|
getInternalSearchParamsState(url.searchParams).updateSearchParams(url.query);
|
||
|
}),
|
||
|
// `URL.prototype.origin` getter
|
||
|
// https://url.spec.whatwg.org/#dom-url-origin
|
||
|
origin: accessorDescriptor(getOrigin),
|
||
|
// `URL.prototype.protocol` accessors pair
|
||
|
// https://url.spec.whatwg.org/#dom-url-protocol
|
||
|
protocol: accessorDescriptor(getProtocol, function (protocol) {
|
||
|
var url = getInternalURLState(this);
|
||
|
parseURL(url, String(protocol) + ':', SCHEME_START);
|
||
|
}),
|
||
|
// `URL.prototype.username` accessors pair
|
||
|
// https://url.spec.whatwg.org/#dom-url-username
|
||
|
username: accessorDescriptor(getUsername, function (username) {
|
||
|
var url = getInternalURLState(this);
|
||
|
var codePoints = arrayFrom(String(username));
|
||
|
if (cannotHaveUsernamePasswordPort(url)) return;
|
||
|
url.username = '';
|
||
|
for (var i = 0; i < codePoints.length; i++) {
|
||
|
url.username += percentEncode(codePoints[i], userinfoPercentEncodeSet);
|
||
|
}
|
||
|
}),
|
||
|
// `URL.prototype.password` accessors pair
|
||
|
// https://url.spec.whatwg.org/#dom-url-password
|
||
|
password: accessorDescriptor(getPassword, function (password) {
|
||
|
var url = getInternalURLState(this);
|
||
|
var codePoints = arrayFrom(String(password));
|
||
|
if (cannotHaveUsernamePasswordPort(url)) return;
|
||
|
url.password = '';
|
||
|
for (var i = 0; i < codePoints.length; i++) {
|
||
|
url.password += percentEncode(codePoints[i], userinfoPercentEncodeSet);
|
||
|
}
|
||
|
}),
|
||
|
// `URL.prototype.host` accessors pair
|
||
|
// https://url.spec.whatwg.org/#dom-url-host
|
||
|
host: accessorDescriptor(getHost, function (host) {
|
||
|
var url = getInternalURLState(this);
|
||
|
if (url.cannotBeABaseURL) return;
|
||
|
parseURL(url, String(host), HOST);
|
||
|
}),
|
||
|
// `URL.prototype.hostname` accessors pair
|
||
|
// https://url.spec.whatwg.org/#dom-url-hostname
|
||
|
hostname: accessorDescriptor(getHostname, function (hostname) {
|
||
|
var url = getInternalURLState(this);
|
||
|
if (url.cannotBeABaseURL) return;
|
||
|
parseURL(url, String(hostname), HOSTNAME);
|
||
|
}),
|
||
|
// `URL.prototype.port` accessors pair
|
||
|
// https://url.spec.whatwg.org/#dom-url-port
|
||
|
port: accessorDescriptor(getPort, function (port) {
|
||
|
var url = getInternalURLState(this);
|
||
|
if (cannotHaveUsernamePasswordPort(url)) return;
|
||
|
port = String(port);
|
||
|
if (port == '') url.port = null;
|
||
|
else parseURL(url, port, PORT);
|
||
|
}),
|
||
|
// `URL.prototype.pathname` accessors pair
|
||
|
// https://url.spec.whatwg.org/#dom-url-pathname
|
||
|
pathname: accessorDescriptor(getPathname, function (pathname) {
|
||
|
var url = getInternalURLState(this);
|
||
|
if (url.cannotBeABaseURL) return;
|
||
|
url.path = [];
|
||
|
parseURL(url, pathname + '', PATH_START);
|
||
|
}),
|
||
|
// `URL.prototype.search` accessors pair
|
||
|
// https://url.spec.whatwg.org/#dom-url-search
|
||
|
search: accessorDescriptor(getSearch, function (search) {
|
||
|
var url = getInternalURLState(this);
|
||
|
search = String(search);
|
||
|
if (search == '') {
|
||
|
url.query = null;
|
||
|
} else {
|
||
|
if ('?' == search.charAt(0)) search = search.slice(1);
|
||
|
url.query = '';
|
||
|
parseURL(url, search, QUERY);
|
||
|
}
|
||
|
getInternalSearchParamsState(url.searchParams).updateSearchParams(url.query);
|
||
|
}),
|
||
|
// `URL.prototype.searchParams` getter
|
||
|
// https://url.spec.whatwg.org/#dom-url-searchparams
|
||
|
searchParams: accessorDescriptor(getSearchParams),
|
||
|
// `URL.prototype.hash` accessors pair
|
||
|
// https://url.spec.whatwg.org/#dom-url-hash
|
||
|
hash: accessorDescriptor(getHash, function (hash) {
|
||
|
var url = getInternalURLState(this);
|
||
|
hash = String(hash);
|
||
|
if (hash == '') {
|
||
|
url.fragment = null;
|
||
|
return;
|
||
|
}
|
||
|
if ('#' == hash.charAt(0)) hash = hash.slice(1);
|
||
|
url.fragment = '';
|
||
|
parseURL(url, hash, FRAGMENT);
|
||
|
})
|
||
|
});
|
||
|
}
|
||
|
|
||
|
// `URL.prototype.toJSON` method
|
||
|
// https://url.spec.whatwg.org/#dom-url-tojson
|
||
|
redefine(URLPrototype, 'toJSON', function toJSON() {
|
||
|
return serializeURL.call(this);
|
||
|
}, { enumerable: true });
|
||
|
|
||
|
// `URL.prototype.toString` method
|
||
|
// https://url.spec.whatwg.org/#URL-stringification-behavior
|
||
|
redefine(URLPrototype, 'toString', function toString() {
|
||
|
return serializeURL.call(this);
|
||
|
}, { enumerable: true });
|
||
|
|
||
|
if (NativeURL) {
|
||
|
var nativeCreateObjectURL = NativeURL.createObjectURL;
|
||
|
var nativeRevokeObjectURL = NativeURL.revokeObjectURL;
|
||
|
// `URL.createObjectURL` method
|
||
|
// https://developer.mozilla.org/en-US/docs/Web/API/URL/createObjectURL
|
||
|
// eslint-disable-next-line no-unused-vars -- required for `.length`
|
||
|
if (nativeCreateObjectURL) redefine(URLConstructor, 'createObjectURL', function createObjectURL(blob) {
|
||
|
return nativeCreateObjectURL.apply(NativeURL, arguments);
|
||
|
});
|
||
|
// `URL.revokeObjectURL` method
|
||
|
// https://developer.mozilla.org/en-US/docs/Web/API/URL/revokeObjectURL
|
||
|
// eslint-disable-next-line no-unused-vars -- required for `.length`
|
||
|
if (nativeRevokeObjectURL) redefine(URLConstructor, 'revokeObjectURL', function revokeObjectURL(url) {
|
||
|
return nativeRevokeObjectURL.apply(NativeURL, arguments);
|
||
|
});
|
||
|
}
|
||
|
|
||
|
setToStringTag(URLConstructor, 'URL');
|
||
|
|
||
|
$({ global: true, forced: !USE_NATIVE_URL, sham: !DESCRIPTORS }, {
|
||
|
URL: URLConstructor
|
||
|
});
|