| | |
| | | '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 hasOwn = require('../internals/has-own-property'); |
| | | 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 $toString = require('../internals/to-string'); |
| | | 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-z]/i; |
| | | // eslint-disable-next-line regexp/no-obscure-range -- safe |
| | | var ALPHANUMERIC = /[\d+-.a-z]/i; |
| | | var DIGIT = /\d/; |
| | | var HEX_START = /^0x/i; |
| | | var OCT = /^[0-7]+$/; |
| | | var DEC = /^\d+$/; |
| | | var HEX = /^[\da-f]+$/i; |
| | | /* eslint-disable regexp/no-control-character -- 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-\u0020]+|[\u0000-\u0020]+$/g; |
| | | var TAB_AND_NEW_LINE = /[\t\n\r]/g; |
| | | /* eslint-enable regexp/no-control-character -- 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 chr = function () { |
| | | return input.charAt(pointer); |
| | | }; |
| | | |
| | | if (chr() == ':') { |
| | | if (input.charAt(1) != ':') return; |
| | | pointer += 2; |
| | | pieceIndex++; |
| | | compress = pieceIndex; |
| | | } |
| | | while (chr()) { |
| | | if (pieceIndex == 8) return; |
| | | if (chr() == ':') { |
| | | if (compress !== null) return; |
| | | pointer++; |
| | | pieceIndex++; |
| | | compress = pieceIndex; |
| | | continue; |
| | | } |
| | | value = length = 0; |
| | | while (length < 4 && HEX.test(chr())) { |
| | | value = value * 16 + parseInt(chr(), 16); |
| | | pointer++; |
| | | length++; |
| | | } |
| | | if (chr() == '.') { |
| | | if (length == 0) return; |
| | | pointer -= length; |
| | | if (pieceIndex > 6) return; |
| | | numbersSeen = 0; |
| | | while (chr()) { |
| | | ipv4Piece = null; |
| | | if (numbersSeen > 0) { |
| | | if (chr() == '.' && numbersSeen < 4) pointer++; |
| | | else return; |
| | | } |
| | | if (!DIGIT.test(chr())) return; |
| | | while (DIGIT.test(chr())) { |
| | | number = parseInt(chr(), 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 (chr() == ':') { |
| | | pointer++; |
| | | if (!chr()) return; |
| | | } else if (chr()) 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 (chr, set) { |
| | | var code = codeAt(chr, 0); |
| | | return code > 0x20 && code < 0x7F && !hasOwn(set, chr) ? chr : encodeURIComponent(chr); |
| | | }; |
| | | |
| | | var specialSchemes = { |
| | | ftp: 21, |
| | | file: null, |
| | | http: 80, |
| | | https: 443, |
| | | ws: 80, |
| | | wss: 443 |
| | | }; |
| | | |
| | | var isSpecial = function (url) { |
| | | return hasOwn(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, chr, 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) { |
| | | chr = codePoints[pointer]; |
| | | switch (state) { |
| | | case SCHEME_START: |
| | | if (chr && ALPHA.test(chr)) { |
| | | buffer += chr.toLowerCase(); |
| | | state = SCHEME; |
| | | } else if (!stateOverride) { |
| | | state = NO_SCHEME; |
| | | continue; |
| | | } else return INVALID_SCHEME; |
| | | break; |
| | | |
| | | case SCHEME: |
| | | if (chr && (ALPHANUMERIC.test(chr) || chr == '+' || chr == '-' || chr == '.')) { |
| | | buffer += chr.toLowerCase(); |
| | | } else if (chr == ':') { |
| | | if (stateOverride && ( |
| | | (isSpecial(url) != hasOwn(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 && chr != '#')) return INVALID_SCHEME; |
| | | if (base.cannotBeABaseURL && chr == '#') { |
| | | 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 (chr == '/' && codePoints[pointer + 1] == '/') { |
| | | state = SPECIAL_AUTHORITY_IGNORE_SLASHES; |
| | | pointer++; |
| | | } else { |
| | | state = RELATIVE; |
| | | continue; |
| | | } break; |
| | | |
| | | case PATH_OR_AUTHORITY: |
| | | if (chr == '/') { |
| | | state = AUTHORITY; |
| | | break; |
| | | } else { |
| | | state = PATH; |
| | | continue; |
| | | } |
| | | |
| | | case RELATIVE: |
| | | url.scheme = base.scheme; |
| | | if (chr == 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 (chr == '/' || (chr == '\\' && isSpecial(url))) { |
| | | state = RELATIVE_SLASH; |
| | | } else if (chr == '?') { |
| | | 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 (chr == '#') { |
| | | 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) && (chr == '/' || chr == '\\')) { |
| | | state = SPECIAL_AUTHORITY_IGNORE_SLASHES; |
| | | } else if (chr == '/') { |
| | | 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 (chr != '/' || buffer.charAt(pointer + 1) != '/') continue; |
| | | pointer++; |
| | | break; |
| | | |
| | | case SPECIAL_AUTHORITY_IGNORE_SLASHES: |
| | | if (chr != '/' && chr != '\\') { |
| | | state = AUTHORITY; |
| | | continue; |
| | | } break; |
| | | |
| | | case AUTHORITY: |
| | | if (chr == '@') { |
| | | 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 ( |
| | | chr == EOF || chr == '/' || chr == '?' || chr == '#' || |
| | | (chr == '\\' && isSpecial(url)) |
| | | ) { |
| | | if (seenAt && buffer == '') return INVALID_AUTHORITY; |
| | | pointer -= arrayFrom(buffer).length + 1; |
| | | buffer = ''; |
| | | state = HOST; |
| | | } else buffer += chr; |
| | | break; |
| | | |
| | | case HOST: |
| | | case HOSTNAME: |
| | | if (stateOverride && url.scheme == 'file') { |
| | | state = FILE_HOST; |
| | | continue; |
| | | } else if (chr == ':' && !seenBracket) { |
| | | if (buffer == '') return INVALID_HOST; |
| | | failure = parseHost(url, buffer); |
| | | if (failure) return failure; |
| | | buffer = ''; |
| | | state = PORT; |
| | | if (stateOverride == HOSTNAME) return; |
| | | } else if ( |
| | | chr == EOF || chr == '/' || chr == '?' || chr == '#' || |
| | | (chr == '\\' && 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 (chr == '[') seenBracket = true; |
| | | else if (chr == ']') seenBracket = false; |
| | | buffer += chr; |
| | | } break; |
| | | |
| | | case PORT: |
| | | if (DIGIT.test(chr)) { |
| | | buffer += chr; |
| | | } else if ( |
| | | chr == EOF || chr == '/' || chr == '?' || chr == '#' || |
| | | (chr == '\\' && 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 (chr == '/' || chr == '\\') state = FILE_SLASH; |
| | | else if (base && base.scheme == 'file') { |
| | | if (chr == EOF) { |
| | | url.host = base.host; |
| | | url.path = base.path.slice(); |
| | | url.query = base.query; |
| | | } else if (chr == '?') { |
| | | url.host = base.host; |
| | | url.path = base.path.slice(); |
| | | url.query = ''; |
| | | state = QUERY; |
| | | } else if (chr == '#') { |
| | | 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 (chr == '/' || chr == '\\') { |
| | | 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 (chr == EOF || chr == '/' || chr == '\\' || chr == '?' || chr == '#') { |
| | | 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 += chr; |
| | | break; |
| | | |
| | | case PATH_START: |
| | | if (isSpecial(url)) { |
| | | state = PATH; |
| | | if (chr != '/' && chr != '\\') continue; |
| | | } else if (!stateOverride && chr == '?') { |
| | | url.query = ''; |
| | | state = QUERY; |
| | | } else if (!stateOverride && chr == '#') { |
| | | url.fragment = ''; |
| | | state = FRAGMENT; |
| | | } else if (chr != EOF) { |
| | | state = PATH; |
| | | if (chr != '/') continue; |
| | | } break; |
| | | |
| | | case PATH: |
| | | if ( |
| | | chr == EOF || chr == '/' || |
| | | (chr == '\\' && isSpecial(url)) || |
| | | (!stateOverride && (chr == '?' || chr == '#')) |
| | | ) { |
| | | if (isDoubleDot(buffer)) { |
| | | shortenURLsPath(url); |
| | | if (chr != '/' && !(chr == '\\' && isSpecial(url))) { |
| | | url.path.push(''); |
| | | } |
| | | } else if (isSingleDot(buffer)) { |
| | | if (chr != '/' && !(chr == '\\' && 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' && (chr == EOF || chr == '?' || chr == '#')) { |
| | | while (url.path.length > 1 && url.path[0] === '') { |
| | | url.path.shift(); |
| | | } |
| | | } |
| | | if (chr == '?') { |
| | | url.query = ''; |
| | | state = QUERY; |
| | | } else if (chr == '#') { |
| | | url.fragment = ''; |
| | | state = FRAGMENT; |
| | | } |
| | | } else { |
| | | buffer += percentEncode(chr, pathPercentEncodeSet); |
| | | } break; |
| | | |
| | | case CANNOT_BE_A_BASE_URL_PATH: |
| | | if (chr == '?') { |
| | | url.query = ''; |
| | | state = QUERY; |
| | | } else if (chr == '#') { |
| | | url.fragment = ''; |
| | | state = FRAGMENT; |
| | | } else if (chr != EOF) { |
| | | url.path[0] += percentEncode(chr, C0ControlPercentEncodeSet); |
| | | } break; |
| | | |
| | | case QUERY: |
| | | if (!stateOverride && chr == '#') { |
| | | url.fragment = ''; |
| | | state = FRAGMENT; |
| | | } else if (chr != EOF) { |
| | | if (chr == "'" && isSpecial(url)) url.query += '%27'; |
| | | else if (chr == '#') url.query += '%23'; |
| | | else url.query += percentEncode(chr, C0ControlPercentEncodeSet); |
| | | } break; |
| | | |
| | | case FRAGMENT: |
| | | if (chr != EOF) url.fragment += percentEncode(chr, 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 = $toString(url); |
| | | var state = setInternalState(that, { type: 'URL' }); |
| | | var baseState, failure; |
| | | if (base !== undefined) { |
| | | if (base instanceof URLConstructor) baseState = getInternalURLState(base); |
| | | else { |
| | | failure = parseURL(baseState = {}, $toString(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 = $toString(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, $toString(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($toString(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($toString(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, $toString(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, $toString(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 = $toString(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, $toString(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 = $toString(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 = $toString(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 |
| | | }); |
| | | // TODO: Remove this module from `core-js@4` since it's replaced to module below |
| | | require('../modules/web.url.constructor'); |