web.url.constructor.js 35 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048
  1. 'use strict';
  2. // TODO: in core-js@4, move /modules/ dependencies to public entries for better optimization by tools like `preset-env`
  3. require('../modules/es.string.iterator');
  4. var $ = require('../internals/export');
  5. var DESCRIPTORS = require('../internals/descriptors');
  6. var USE_NATIVE_URL = require('../internals/url-constructor-detection');
  7. var global = require('../internals/global');
  8. var bind = require('../internals/function-bind-context');
  9. var uncurryThis = require('../internals/function-uncurry-this');
  10. var defineBuiltIn = require('../internals/define-built-in');
  11. var defineBuiltInAccessor = require('../internals/define-built-in-accessor');
  12. var anInstance = require('../internals/an-instance');
  13. var hasOwn = require('../internals/has-own-property');
  14. var assign = require('../internals/object-assign');
  15. var arrayFrom = require('../internals/array-from');
  16. var arraySlice = require('../internals/array-slice-simple');
  17. var codeAt = require('../internals/string-multibyte').codeAt;
  18. var toASCII = require('../internals/string-punycode-to-ascii');
  19. var $toString = require('../internals/to-string');
  20. var setToStringTag = require('../internals/set-to-string-tag');
  21. var validateArgumentsLength = require('../internals/validate-arguments-length');
  22. var URLSearchParamsModule = require('../modules/web.url-search-params.constructor');
  23. var InternalStateModule = require('../internals/internal-state');
  24. var setInternalState = InternalStateModule.set;
  25. var getInternalURLState = InternalStateModule.getterFor('URL');
  26. var URLSearchParams = URLSearchParamsModule.URLSearchParams;
  27. var getInternalSearchParamsState = URLSearchParamsModule.getState;
  28. var NativeURL = global.URL;
  29. var TypeError = global.TypeError;
  30. var parseInt = global.parseInt;
  31. var floor = Math.floor;
  32. var pow = Math.pow;
  33. var charAt = uncurryThis(''.charAt);
  34. var exec = uncurryThis(/./.exec);
  35. var join = uncurryThis([].join);
  36. var numberToString = uncurryThis(1.0.toString);
  37. var pop = uncurryThis([].pop);
  38. var push = uncurryThis([].push);
  39. var replace = uncurryThis(''.replace);
  40. var shift = uncurryThis([].shift);
  41. var split = uncurryThis(''.split);
  42. var stringSlice = uncurryThis(''.slice);
  43. var toLowerCase = uncurryThis(''.toLowerCase);
  44. var unshift = uncurryThis([].unshift);
  45. var INVALID_AUTHORITY = 'Invalid authority';
  46. var INVALID_SCHEME = 'Invalid scheme';
  47. var INVALID_HOST = 'Invalid host';
  48. var INVALID_PORT = 'Invalid port';
  49. var ALPHA = /[a-z]/i;
  50. // eslint-disable-next-line regexp/no-obscure-range -- safe
  51. var ALPHANUMERIC = /[\d+-.a-z]/i;
  52. var DIGIT = /\d/;
  53. var HEX_START = /^0x/i;
  54. var OCT = /^[0-7]+$/;
  55. var DEC = /^\d+$/;
  56. var HEX = /^[\da-f]+$/i;
  57. /* eslint-disable regexp/no-control-character -- safe */
  58. var FORBIDDEN_HOST_CODE_POINT = /[\0\t\n\r #%/:<>?@[\\\]^|]/;
  59. var FORBIDDEN_HOST_CODE_POINT_EXCLUDING_PERCENT = /[\0\t\n\r #/:<>?@[\\\]^|]/;
  60. var LEADING_C0_CONTROL_OR_SPACE = /^[\u0000-\u0020]+/;
  61. var TRAILING_C0_CONTROL_OR_SPACE = /(^|[^\u0000-\u0020])[\u0000-\u0020]+$/;
  62. var TAB_AND_NEW_LINE = /[\t\n\r]/g;
  63. /* eslint-enable regexp/no-control-character -- safe */
  64. var EOF;
  65. // https://url.spec.whatwg.org/#ipv4-number-parser
  66. var parseIPv4 = function (input) {
  67. var parts = split(input, '.');
  68. var partsLength, numbers, index, part, radix, number, ipv4;
  69. if (parts.length && parts[parts.length - 1] === '') {
  70. parts.length--;
  71. }
  72. partsLength = parts.length;
  73. if (partsLength > 4) return input;
  74. numbers = [];
  75. for (index = 0; index < partsLength; index++) {
  76. part = parts[index];
  77. if (part === '') return input;
  78. radix = 10;
  79. if (part.length > 1 && charAt(part, 0) === '0') {
  80. radix = exec(HEX_START, part) ? 16 : 8;
  81. part = stringSlice(part, radix === 8 ? 1 : 2);
  82. }
  83. if (part === '') {
  84. number = 0;
  85. } else {
  86. if (!exec(radix === 10 ? DEC : radix === 8 ? OCT : HEX, part)) return input;
  87. number = parseInt(part, radix);
  88. }
  89. push(numbers, number);
  90. }
  91. for (index = 0; index < partsLength; index++) {
  92. number = numbers[index];
  93. if (index === partsLength - 1) {
  94. if (number >= pow(256, 5 - partsLength)) return null;
  95. } else if (number > 255) return null;
  96. }
  97. ipv4 = pop(numbers);
  98. for (index = 0; index < numbers.length; index++) {
  99. ipv4 += numbers[index] * pow(256, 3 - index);
  100. }
  101. return ipv4;
  102. };
  103. // https://url.spec.whatwg.org/#concept-ipv6-parser
  104. // eslint-disable-next-line max-statements -- TODO
  105. var parseIPv6 = function (input) {
  106. var address = [0, 0, 0, 0, 0, 0, 0, 0];
  107. var pieceIndex = 0;
  108. var compress = null;
  109. var pointer = 0;
  110. var value, length, numbersSeen, ipv4Piece, number, swaps, swap;
  111. var chr = function () {
  112. return charAt(input, pointer);
  113. };
  114. if (chr() === ':') {
  115. if (charAt(input, 1) !== ':') return;
  116. pointer += 2;
  117. pieceIndex++;
  118. compress = pieceIndex;
  119. }
  120. while (chr()) {
  121. if (pieceIndex === 8) return;
  122. if (chr() === ':') {
  123. if (compress !== null) return;
  124. pointer++;
  125. pieceIndex++;
  126. compress = pieceIndex;
  127. continue;
  128. }
  129. value = length = 0;
  130. while (length < 4 && exec(HEX, chr())) {
  131. value = value * 16 + parseInt(chr(), 16);
  132. pointer++;
  133. length++;
  134. }
  135. if (chr() === '.') {
  136. if (length === 0) return;
  137. pointer -= length;
  138. if (pieceIndex > 6) return;
  139. numbersSeen = 0;
  140. while (chr()) {
  141. ipv4Piece = null;
  142. if (numbersSeen > 0) {
  143. if (chr() === '.' && numbersSeen < 4) pointer++;
  144. else return;
  145. }
  146. if (!exec(DIGIT, chr())) return;
  147. while (exec(DIGIT, chr())) {
  148. number = parseInt(chr(), 10);
  149. if (ipv4Piece === null) ipv4Piece = number;
  150. else if (ipv4Piece === 0) return;
  151. else ipv4Piece = ipv4Piece * 10 + number;
  152. if (ipv4Piece > 255) return;
  153. pointer++;
  154. }
  155. address[pieceIndex] = address[pieceIndex] * 256 + ipv4Piece;
  156. numbersSeen++;
  157. if (numbersSeen === 2 || numbersSeen === 4) pieceIndex++;
  158. }
  159. if (numbersSeen !== 4) return;
  160. break;
  161. } else if (chr() === ':') {
  162. pointer++;
  163. if (!chr()) return;
  164. } else if (chr()) return;
  165. address[pieceIndex++] = value;
  166. }
  167. if (compress !== null) {
  168. swaps = pieceIndex - compress;
  169. pieceIndex = 7;
  170. while (pieceIndex !== 0 && swaps > 0) {
  171. swap = address[pieceIndex];
  172. address[pieceIndex--] = address[compress + swaps - 1];
  173. address[compress + --swaps] = swap;
  174. }
  175. } else if (pieceIndex !== 8) return;
  176. return address;
  177. };
  178. var findLongestZeroSequence = function (ipv6) {
  179. var maxIndex = null;
  180. var maxLength = 1;
  181. var currStart = null;
  182. var currLength = 0;
  183. var index = 0;
  184. for (; index < 8; index++) {
  185. if (ipv6[index] !== 0) {
  186. if (currLength > maxLength) {
  187. maxIndex = currStart;
  188. maxLength = currLength;
  189. }
  190. currStart = null;
  191. currLength = 0;
  192. } else {
  193. if (currStart === null) currStart = index;
  194. ++currLength;
  195. }
  196. }
  197. if (currLength > maxLength) {
  198. maxIndex = currStart;
  199. maxLength = currLength;
  200. }
  201. return maxIndex;
  202. };
  203. // https://url.spec.whatwg.org/#host-serializing
  204. var serializeHost = function (host) {
  205. var result, index, compress, ignore0;
  206. // ipv4
  207. if (typeof host == 'number') {
  208. result = [];
  209. for (index = 0; index < 4; index++) {
  210. unshift(result, host % 256);
  211. host = floor(host / 256);
  212. } return join(result, '.');
  213. // ipv6
  214. } else if (typeof host == 'object') {
  215. result = '';
  216. compress = findLongestZeroSequence(host);
  217. for (index = 0; index < 8; index++) {
  218. if (ignore0 && host[index] === 0) continue;
  219. if (ignore0) ignore0 = false;
  220. if (compress === index) {
  221. result += index ? ':' : '::';
  222. ignore0 = true;
  223. } else {
  224. result += numberToString(host[index], 16);
  225. if (index < 7) result += ':';
  226. }
  227. }
  228. return '[' + result + ']';
  229. } return host;
  230. };
  231. var C0ControlPercentEncodeSet = {};
  232. var fragmentPercentEncodeSet = assign({}, C0ControlPercentEncodeSet, {
  233. ' ': 1, '"': 1, '<': 1, '>': 1, '`': 1
  234. });
  235. var pathPercentEncodeSet = assign({}, fragmentPercentEncodeSet, {
  236. '#': 1, '?': 1, '{': 1, '}': 1
  237. });
  238. var userinfoPercentEncodeSet = assign({}, pathPercentEncodeSet, {
  239. '/': 1, ':': 1, ';': 1, '=': 1, '@': 1, '[': 1, '\\': 1, ']': 1, '^': 1, '|': 1
  240. });
  241. var percentEncode = function (chr, set) {
  242. var code = codeAt(chr, 0);
  243. return code > 0x20 && code < 0x7F && !hasOwn(set, chr) ? chr : encodeURIComponent(chr);
  244. };
  245. // https://url.spec.whatwg.org/#special-scheme
  246. var specialSchemes = {
  247. ftp: 21,
  248. file: null,
  249. http: 80,
  250. https: 443,
  251. ws: 80,
  252. wss: 443
  253. };
  254. // https://url.spec.whatwg.org/#windows-drive-letter
  255. var isWindowsDriveLetter = function (string, normalized) {
  256. var second;
  257. return string.length === 2 && exec(ALPHA, charAt(string, 0))
  258. && ((second = charAt(string, 1)) === ':' || (!normalized && second === '|'));
  259. };
  260. // https://url.spec.whatwg.org/#start-with-a-windows-drive-letter
  261. var startsWithWindowsDriveLetter = function (string) {
  262. var third;
  263. return string.length > 1 && isWindowsDriveLetter(stringSlice(string, 0, 2)) && (
  264. string.length === 2 ||
  265. ((third = charAt(string, 2)) === '/' || third === '\\' || third === '?' || third === '#')
  266. );
  267. };
  268. // https://url.spec.whatwg.org/#single-dot-path-segment
  269. var isSingleDot = function (segment) {
  270. return segment === '.' || toLowerCase(segment) === '%2e';
  271. };
  272. // https://url.spec.whatwg.org/#double-dot-path-segment
  273. var isDoubleDot = function (segment) {
  274. segment = toLowerCase(segment);
  275. return segment === '..' || segment === '%2e.' || segment === '.%2e' || segment === '%2e%2e';
  276. };
  277. // States:
  278. var SCHEME_START = {};
  279. var SCHEME = {};
  280. var NO_SCHEME = {};
  281. var SPECIAL_RELATIVE_OR_AUTHORITY = {};
  282. var PATH_OR_AUTHORITY = {};
  283. var RELATIVE = {};
  284. var RELATIVE_SLASH = {};
  285. var SPECIAL_AUTHORITY_SLASHES = {};
  286. var SPECIAL_AUTHORITY_IGNORE_SLASHES = {};
  287. var AUTHORITY = {};
  288. var HOST = {};
  289. var HOSTNAME = {};
  290. var PORT = {};
  291. var FILE = {};
  292. var FILE_SLASH = {};
  293. var FILE_HOST = {};
  294. var PATH_START = {};
  295. var PATH = {};
  296. var CANNOT_BE_A_BASE_URL_PATH = {};
  297. var QUERY = {};
  298. var FRAGMENT = {};
  299. var URLState = function (url, isBase, base) {
  300. var urlString = $toString(url);
  301. var baseState, failure, searchParams;
  302. if (isBase) {
  303. failure = this.parse(urlString);
  304. if (failure) throw TypeError(failure);
  305. this.searchParams = null;
  306. } else {
  307. if (base !== undefined) baseState = new URLState(base, true);
  308. failure = this.parse(urlString, null, baseState);
  309. if (failure) throw TypeError(failure);
  310. searchParams = getInternalSearchParamsState(new URLSearchParams());
  311. searchParams.bindURL(this);
  312. this.searchParams = searchParams;
  313. }
  314. };
  315. URLState.prototype = {
  316. type: 'URL',
  317. // https://url.spec.whatwg.org/#url-parsing
  318. // eslint-disable-next-line max-statements -- TODO
  319. parse: function (input, stateOverride, base) {
  320. var url = this;
  321. var state = stateOverride || SCHEME_START;
  322. var pointer = 0;
  323. var buffer = '';
  324. var seenAt = false;
  325. var seenBracket = false;
  326. var seenPasswordToken = false;
  327. var codePoints, chr, bufferCodePoints, failure;
  328. input = $toString(input);
  329. if (!stateOverride) {
  330. url.scheme = '';
  331. url.username = '';
  332. url.password = '';
  333. url.host = null;
  334. url.port = null;
  335. url.path = [];
  336. url.query = null;
  337. url.fragment = null;
  338. url.cannotBeABaseURL = false;
  339. input = replace(input, LEADING_C0_CONTROL_OR_SPACE, '');
  340. input = replace(input, TRAILING_C0_CONTROL_OR_SPACE, '$1');
  341. }
  342. input = replace(input, TAB_AND_NEW_LINE, '');
  343. codePoints = arrayFrom(input);
  344. while (pointer <= codePoints.length) {
  345. chr = codePoints[pointer];
  346. switch (state) {
  347. case SCHEME_START:
  348. if (chr && exec(ALPHA, chr)) {
  349. buffer += toLowerCase(chr);
  350. state = SCHEME;
  351. } else if (!stateOverride) {
  352. state = NO_SCHEME;
  353. continue;
  354. } else return INVALID_SCHEME;
  355. break;
  356. case SCHEME:
  357. if (chr && (exec(ALPHANUMERIC, chr) || chr === '+' || chr === '-' || chr === '.')) {
  358. buffer += toLowerCase(chr);
  359. } else if (chr === ':') {
  360. if (stateOverride && (
  361. (url.isSpecial() !== hasOwn(specialSchemes, buffer)) ||
  362. (buffer === 'file' && (url.includesCredentials() || url.port !== null)) ||
  363. (url.scheme === 'file' && !url.host)
  364. )) return;
  365. url.scheme = buffer;
  366. if (stateOverride) {
  367. if (url.isSpecial() && specialSchemes[url.scheme] === url.port) url.port = null;
  368. return;
  369. }
  370. buffer = '';
  371. if (url.scheme === 'file') {
  372. state = FILE;
  373. } else if (url.isSpecial() && base && base.scheme === url.scheme) {
  374. state = SPECIAL_RELATIVE_OR_AUTHORITY;
  375. } else if (url.isSpecial()) {
  376. state = SPECIAL_AUTHORITY_SLASHES;
  377. } else if (codePoints[pointer + 1] === '/') {
  378. state = PATH_OR_AUTHORITY;
  379. pointer++;
  380. } else {
  381. url.cannotBeABaseURL = true;
  382. push(url.path, '');
  383. state = CANNOT_BE_A_BASE_URL_PATH;
  384. }
  385. } else if (!stateOverride) {
  386. buffer = '';
  387. state = NO_SCHEME;
  388. pointer = 0;
  389. continue;
  390. } else return INVALID_SCHEME;
  391. break;
  392. case NO_SCHEME:
  393. if (!base || (base.cannotBeABaseURL && chr !== '#')) return INVALID_SCHEME;
  394. if (base.cannotBeABaseURL && chr === '#') {
  395. url.scheme = base.scheme;
  396. url.path = arraySlice(base.path);
  397. url.query = base.query;
  398. url.fragment = '';
  399. url.cannotBeABaseURL = true;
  400. state = FRAGMENT;
  401. break;
  402. }
  403. state = base.scheme === 'file' ? FILE : RELATIVE;
  404. continue;
  405. case SPECIAL_RELATIVE_OR_AUTHORITY:
  406. if (chr === '/' && codePoints[pointer + 1] === '/') {
  407. state = SPECIAL_AUTHORITY_IGNORE_SLASHES;
  408. pointer++;
  409. } else {
  410. state = RELATIVE;
  411. continue;
  412. } break;
  413. case PATH_OR_AUTHORITY:
  414. if (chr === '/') {
  415. state = AUTHORITY;
  416. break;
  417. } else {
  418. state = PATH;
  419. continue;
  420. }
  421. case RELATIVE:
  422. url.scheme = base.scheme;
  423. if (chr === EOF) {
  424. url.username = base.username;
  425. url.password = base.password;
  426. url.host = base.host;
  427. url.port = base.port;
  428. url.path = arraySlice(base.path);
  429. url.query = base.query;
  430. } else if (chr === '/' || (chr === '\\' && url.isSpecial())) {
  431. state = RELATIVE_SLASH;
  432. } else if (chr === '?') {
  433. url.username = base.username;
  434. url.password = base.password;
  435. url.host = base.host;
  436. url.port = base.port;
  437. url.path = arraySlice(base.path);
  438. url.query = '';
  439. state = QUERY;
  440. } else if (chr === '#') {
  441. url.username = base.username;
  442. url.password = base.password;
  443. url.host = base.host;
  444. url.port = base.port;
  445. url.path = arraySlice(base.path);
  446. url.query = base.query;
  447. url.fragment = '';
  448. state = FRAGMENT;
  449. } else {
  450. url.username = base.username;
  451. url.password = base.password;
  452. url.host = base.host;
  453. url.port = base.port;
  454. url.path = arraySlice(base.path);
  455. url.path.length--;
  456. state = PATH;
  457. continue;
  458. } break;
  459. case RELATIVE_SLASH:
  460. if (url.isSpecial() && (chr === '/' || chr === '\\')) {
  461. state = SPECIAL_AUTHORITY_IGNORE_SLASHES;
  462. } else if (chr === '/') {
  463. state = AUTHORITY;
  464. } else {
  465. url.username = base.username;
  466. url.password = base.password;
  467. url.host = base.host;
  468. url.port = base.port;
  469. state = PATH;
  470. continue;
  471. } break;
  472. case SPECIAL_AUTHORITY_SLASHES:
  473. state = SPECIAL_AUTHORITY_IGNORE_SLASHES;
  474. if (chr !== '/' || charAt(buffer, pointer + 1) !== '/') continue;
  475. pointer++;
  476. break;
  477. case SPECIAL_AUTHORITY_IGNORE_SLASHES:
  478. if (chr !== '/' && chr !== '\\') {
  479. state = AUTHORITY;
  480. continue;
  481. } break;
  482. case AUTHORITY:
  483. if (chr === '@') {
  484. if (seenAt) buffer = '%40' + buffer;
  485. seenAt = true;
  486. bufferCodePoints = arrayFrom(buffer);
  487. for (var i = 0; i < bufferCodePoints.length; i++) {
  488. var codePoint = bufferCodePoints[i];
  489. if (codePoint === ':' && !seenPasswordToken) {
  490. seenPasswordToken = true;
  491. continue;
  492. }
  493. var encodedCodePoints = percentEncode(codePoint, userinfoPercentEncodeSet);
  494. if (seenPasswordToken) url.password += encodedCodePoints;
  495. else url.username += encodedCodePoints;
  496. }
  497. buffer = '';
  498. } else if (
  499. chr === EOF || chr === '/' || chr === '?' || chr === '#' ||
  500. (chr === '\\' && url.isSpecial())
  501. ) {
  502. if (seenAt && buffer === '') return INVALID_AUTHORITY;
  503. pointer -= arrayFrom(buffer).length + 1;
  504. buffer = '';
  505. state = HOST;
  506. } else buffer += chr;
  507. break;
  508. case HOST:
  509. case HOSTNAME:
  510. if (stateOverride && url.scheme === 'file') {
  511. state = FILE_HOST;
  512. continue;
  513. } else if (chr === ':' && !seenBracket) {
  514. if (buffer === '') return INVALID_HOST;
  515. failure = url.parseHost(buffer);
  516. if (failure) return failure;
  517. buffer = '';
  518. state = PORT;
  519. if (stateOverride === HOSTNAME) return;
  520. } else if (
  521. chr === EOF || chr === '/' || chr === '?' || chr === '#' ||
  522. (chr === '\\' && url.isSpecial())
  523. ) {
  524. if (url.isSpecial() && buffer === '') return INVALID_HOST;
  525. if (stateOverride && buffer === '' && (url.includesCredentials() || url.port !== null)) return;
  526. failure = url.parseHost(buffer);
  527. if (failure) return failure;
  528. buffer = '';
  529. state = PATH_START;
  530. if (stateOverride) return;
  531. continue;
  532. } else {
  533. if (chr === '[') seenBracket = true;
  534. else if (chr === ']') seenBracket = false;
  535. buffer += chr;
  536. } break;
  537. case PORT:
  538. if (exec(DIGIT, chr)) {
  539. buffer += chr;
  540. } else if (
  541. chr === EOF || chr === '/' || chr === '?' || chr === '#' ||
  542. (chr === '\\' && url.isSpecial()) ||
  543. stateOverride
  544. ) {
  545. if (buffer !== '') {
  546. var port = parseInt(buffer, 10);
  547. if (port > 0xFFFF) return INVALID_PORT;
  548. url.port = (url.isSpecial() && port === specialSchemes[url.scheme]) ? null : port;
  549. buffer = '';
  550. }
  551. if (stateOverride) return;
  552. state = PATH_START;
  553. continue;
  554. } else return INVALID_PORT;
  555. break;
  556. case FILE:
  557. url.scheme = 'file';
  558. if (chr === '/' || chr === '\\') state = FILE_SLASH;
  559. else if (base && base.scheme === 'file') {
  560. switch (chr) {
  561. case EOF:
  562. url.host = base.host;
  563. url.path = arraySlice(base.path);
  564. url.query = base.query;
  565. break;
  566. case '?':
  567. url.host = base.host;
  568. url.path = arraySlice(base.path);
  569. url.query = '';
  570. state = QUERY;
  571. break;
  572. case '#':
  573. url.host = base.host;
  574. url.path = arraySlice(base.path);
  575. url.query = base.query;
  576. url.fragment = '';
  577. state = FRAGMENT;
  578. break;
  579. default:
  580. if (!startsWithWindowsDriveLetter(join(arraySlice(codePoints, pointer), ''))) {
  581. url.host = base.host;
  582. url.path = arraySlice(base.path);
  583. url.shortenPath();
  584. }
  585. state = PATH;
  586. continue;
  587. }
  588. } else {
  589. state = PATH;
  590. continue;
  591. } break;
  592. case FILE_SLASH:
  593. if (chr === '/' || chr === '\\') {
  594. state = FILE_HOST;
  595. break;
  596. }
  597. if (base && base.scheme === 'file' && !startsWithWindowsDriveLetter(join(arraySlice(codePoints, pointer), ''))) {
  598. if (isWindowsDriveLetter(base.path[0], true)) push(url.path, base.path[0]);
  599. else url.host = base.host;
  600. }
  601. state = PATH;
  602. continue;
  603. case FILE_HOST:
  604. if (chr === EOF || chr === '/' || chr === '\\' || chr === '?' || chr === '#') {
  605. if (!stateOverride && isWindowsDriveLetter(buffer)) {
  606. state = PATH;
  607. } else if (buffer === '') {
  608. url.host = '';
  609. if (stateOverride) return;
  610. state = PATH_START;
  611. } else {
  612. failure = url.parseHost(buffer);
  613. if (failure) return failure;
  614. if (url.host === 'localhost') url.host = '';
  615. if (stateOverride) return;
  616. buffer = '';
  617. state = PATH_START;
  618. } continue;
  619. } else buffer += chr;
  620. break;
  621. case PATH_START:
  622. if (url.isSpecial()) {
  623. state = PATH;
  624. if (chr !== '/' && chr !== '\\') continue;
  625. } else if (!stateOverride && chr === '?') {
  626. url.query = '';
  627. state = QUERY;
  628. } else if (!stateOverride && chr === '#') {
  629. url.fragment = '';
  630. state = FRAGMENT;
  631. } else if (chr !== EOF) {
  632. state = PATH;
  633. if (chr !== '/') continue;
  634. } break;
  635. case PATH:
  636. if (
  637. chr === EOF || chr === '/' ||
  638. (chr === '\\' && url.isSpecial()) ||
  639. (!stateOverride && (chr === '?' || chr === '#'))
  640. ) {
  641. if (isDoubleDot(buffer)) {
  642. url.shortenPath();
  643. if (chr !== '/' && !(chr === '\\' && url.isSpecial())) {
  644. push(url.path, '');
  645. }
  646. } else if (isSingleDot(buffer)) {
  647. if (chr !== '/' && !(chr === '\\' && url.isSpecial())) {
  648. push(url.path, '');
  649. }
  650. } else {
  651. if (url.scheme === 'file' && !url.path.length && isWindowsDriveLetter(buffer)) {
  652. if (url.host) url.host = '';
  653. buffer = charAt(buffer, 0) + ':'; // normalize windows drive letter
  654. }
  655. push(url.path, buffer);
  656. }
  657. buffer = '';
  658. if (url.scheme === 'file' && (chr === EOF || chr === '?' || chr === '#')) {
  659. while (url.path.length > 1 && url.path[0] === '') {
  660. shift(url.path);
  661. }
  662. }
  663. if (chr === '?') {
  664. url.query = '';
  665. state = QUERY;
  666. } else if (chr === '#') {
  667. url.fragment = '';
  668. state = FRAGMENT;
  669. }
  670. } else {
  671. buffer += percentEncode(chr, pathPercentEncodeSet);
  672. } break;
  673. case CANNOT_BE_A_BASE_URL_PATH:
  674. if (chr === '?') {
  675. url.query = '';
  676. state = QUERY;
  677. } else if (chr === '#') {
  678. url.fragment = '';
  679. state = FRAGMENT;
  680. } else if (chr !== EOF) {
  681. url.path[0] += percentEncode(chr, C0ControlPercentEncodeSet);
  682. } break;
  683. case QUERY:
  684. if (!stateOverride && chr === '#') {
  685. url.fragment = '';
  686. state = FRAGMENT;
  687. } else if (chr !== EOF) {
  688. if (chr === "'" && url.isSpecial()) url.query += '%27';
  689. else if (chr === '#') url.query += '%23';
  690. else url.query += percentEncode(chr, C0ControlPercentEncodeSet);
  691. } break;
  692. case FRAGMENT:
  693. if (chr !== EOF) url.fragment += percentEncode(chr, fragmentPercentEncodeSet);
  694. break;
  695. }
  696. pointer++;
  697. }
  698. },
  699. // https://url.spec.whatwg.org/#host-parsing
  700. parseHost: function (input) {
  701. var result, codePoints, index;
  702. if (charAt(input, 0) === '[') {
  703. if (charAt(input, input.length - 1) !== ']') return INVALID_HOST;
  704. result = parseIPv6(stringSlice(input, 1, -1));
  705. if (!result) return INVALID_HOST;
  706. this.host = result;
  707. // opaque host
  708. } else if (!this.isSpecial()) {
  709. if (exec(FORBIDDEN_HOST_CODE_POINT_EXCLUDING_PERCENT, input)) return INVALID_HOST;
  710. result = '';
  711. codePoints = arrayFrom(input);
  712. for (index = 0; index < codePoints.length; index++) {
  713. result += percentEncode(codePoints[index], C0ControlPercentEncodeSet);
  714. }
  715. this.host = result;
  716. } else {
  717. input = toASCII(input);
  718. if (exec(FORBIDDEN_HOST_CODE_POINT, input)) return INVALID_HOST;
  719. result = parseIPv4(input);
  720. if (result === null) return INVALID_HOST;
  721. this.host = result;
  722. }
  723. },
  724. // https://url.spec.whatwg.org/#cannot-have-a-username-password-port
  725. cannotHaveUsernamePasswordPort: function () {
  726. return !this.host || this.cannotBeABaseURL || this.scheme === 'file';
  727. },
  728. // https://url.spec.whatwg.org/#include-credentials
  729. includesCredentials: function () {
  730. return this.username !== '' || this.password !== '';
  731. },
  732. // https://url.spec.whatwg.org/#is-special
  733. isSpecial: function () {
  734. return hasOwn(specialSchemes, this.scheme);
  735. },
  736. // https://url.spec.whatwg.org/#shorten-a-urls-path
  737. shortenPath: function () {
  738. var path = this.path;
  739. var pathSize = path.length;
  740. if (pathSize && (this.scheme !== 'file' || pathSize !== 1 || !isWindowsDriveLetter(path[0], true))) {
  741. path.length--;
  742. }
  743. },
  744. // https://url.spec.whatwg.org/#concept-url-serializer
  745. serialize: function () {
  746. var url = this;
  747. var scheme = url.scheme;
  748. var username = url.username;
  749. var password = url.password;
  750. var host = url.host;
  751. var port = url.port;
  752. var path = url.path;
  753. var query = url.query;
  754. var fragment = url.fragment;
  755. var output = scheme + ':';
  756. if (host !== null) {
  757. output += '//';
  758. if (url.includesCredentials()) {
  759. output += username + (password ? ':' + password : '') + '@';
  760. }
  761. output += serializeHost(host);
  762. if (port !== null) output += ':' + port;
  763. } else if (scheme === 'file') output += '//';
  764. output += url.cannotBeABaseURL ? path[0] : path.length ? '/' + join(path, '/') : '';
  765. if (query !== null) output += '?' + query;
  766. if (fragment !== null) output += '#' + fragment;
  767. return output;
  768. },
  769. // https://url.spec.whatwg.org/#dom-url-href
  770. setHref: function (href) {
  771. var failure = this.parse(href);
  772. if (failure) throw TypeError(failure);
  773. this.searchParams.update();
  774. },
  775. // https://url.spec.whatwg.org/#dom-url-origin
  776. getOrigin: function () {
  777. var scheme = this.scheme;
  778. var port = this.port;
  779. if (scheme === 'blob') try {
  780. return new URLConstructor(scheme.path[0]).origin;
  781. } catch (error) {
  782. return 'null';
  783. }
  784. if (scheme === 'file' || !this.isSpecial()) return 'null';
  785. return scheme + '://' + serializeHost(this.host) + (port !== null ? ':' + port : '');
  786. },
  787. // https://url.spec.whatwg.org/#dom-url-protocol
  788. getProtocol: function () {
  789. return this.scheme + ':';
  790. },
  791. setProtocol: function (protocol) {
  792. this.parse($toString(protocol) + ':', SCHEME_START);
  793. },
  794. // https://url.spec.whatwg.org/#dom-url-username
  795. getUsername: function () {
  796. return this.username;
  797. },
  798. setUsername: function (username) {
  799. var codePoints = arrayFrom($toString(username));
  800. if (this.cannotHaveUsernamePasswordPort()) return;
  801. this.username = '';
  802. for (var i = 0; i < codePoints.length; i++) {
  803. this.username += percentEncode(codePoints[i], userinfoPercentEncodeSet);
  804. }
  805. },
  806. // https://url.spec.whatwg.org/#dom-url-password
  807. getPassword: function () {
  808. return this.password;
  809. },
  810. setPassword: function (password) {
  811. var codePoints = arrayFrom($toString(password));
  812. if (this.cannotHaveUsernamePasswordPort()) return;
  813. this.password = '';
  814. for (var i = 0; i < codePoints.length; i++) {
  815. this.password += percentEncode(codePoints[i], userinfoPercentEncodeSet);
  816. }
  817. },
  818. // https://url.spec.whatwg.org/#dom-url-host
  819. getHost: function () {
  820. var host = this.host;
  821. var port = this.port;
  822. return host === null ? ''
  823. : port === null ? serializeHost(host)
  824. : serializeHost(host) + ':' + port;
  825. },
  826. setHost: function (host) {
  827. if (this.cannotBeABaseURL) return;
  828. this.parse(host, HOST);
  829. },
  830. // https://url.spec.whatwg.org/#dom-url-hostname
  831. getHostname: function () {
  832. var host = this.host;
  833. return host === null ? '' : serializeHost(host);
  834. },
  835. setHostname: function (hostname) {
  836. if (this.cannotBeABaseURL) return;
  837. this.parse(hostname, HOSTNAME);
  838. },
  839. // https://url.spec.whatwg.org/#dom-url-port
  840. getPort: function () {
  841. var port = this.port;
  842. return port === null ? '' : $toString(port);
  843. },
  844. setPort: function (port) {
  845. if (this.cannotHaveUsernamePasswordPort()) return;
  846. port = $toString(port);
  847. if (port === '') this.port = null;
  848. else this.parse(port, PORT);
  849. },
  850. // https://url.spec.whatwg.org/#dom-url-pathname
  851. getPathname: function () {
  852. var path = this.path;
  853. return this.cannotBeABaseURL ? path[0] : path.length ? '/' + join(path, '/') : '';
  854. },
  855. setPathname: function (pathname) {
  856. if (this.cannotBeABaseURL) return;
  857. this.path = [];
  858. this.parse(pathname, PATH_START);
  859. },
  860. // https://url.spec.whatwg.org/#dom-url-search
  861. getSearch: function () {
  862. var query = this.query;
  863. return query ? '?' + query : '';
  864. },
  865. setSearch: function (search) {
  866. search = $toString(search);
  867. if (search === '') {
  868. this.query = null;
  869. } else {
  870. if (charAt(search, 0) === '?') search = stringSlice(search, 1);
  871. this.query = '';
  872. this.parse(search, QUERY);
  873. }
  874. this.searchParams.update();
  875. },
  876. // https://url.spec.whatwg.org/#dom-url-searchparams
  877. getSearchParams: function () {
  878. return this.searchParams.facade;
  879. },
  880. // https://url.spec.whatwg.org/#dom-url-hash
  881. getHash: function () {
  882. var fragment = this.fragment;
  883. return fragment ? '#' + fragment : '';
  884. },
  885. setHash: function (hash) {
  886. hash = $toString(hash);
  887. if (hash === '') {
  888. this.fragment = null;
  889. return;
  890. }
  891. if (charAt(hash, 0) === '#') hash = stringSlice(hash, 1);
  892. this.fragment = '';
  893. this.parse(hash, FRAGMENT);
  894. },
  895. update: function () {
  896. this.query = this.searchParams.serialize() || null;
  897. }
  898. };
  899. // `URL` constructor
  900. // https://url.spec.whatwg.org/#url-class
  901. var URLConstructor = function URL(url /* , base */) {
  902. var that = anInstance(this, URLPrototype);
  903. var base = validateArgumentsLength(arguments.length, 1) > 1 ? arguments[1] : undefined;
  904. var state = setInternalState(that, new URLState(url, false, base));
  905. if (!DESCRIPTORS) {
  906. that.href = state.serialize();
  907. that.origin = state.getOrigin();
  908. that.protocol = state.getProtocol();
  909. that.username = state.getUsername();
  910. that.password = state.getPassword();
  911. that.host = state.getHost();
  912. that.hostname = state.getHostname();
  913. that.port = state.getPort();
  914. that.pathname = state.getPathname();
  915. that.search = state.getSearch();
  916. that.searchParams = state.getSearchParams();
  917. that.hash = state.getHash();
  918. }
  919. };
  920. var URLPrototype = URLConstructor.prototype;
  921. var accessorDescriptor = function (getter, setter) {
  922. return {
  923. get: function () {
  924. return getInternalURLState(this)[getter]();
  925. },
  926. set: setter && function (value) {
  927. return getInternalURLState(this)[setter](value);
  928. },
  929. configurable: true,
  930. enumerable: true
  931. };
  932. };
  933. if (DESCRIPTORS) {
  934. // `URL.prototype.href` accessors pair
  935. // https://url.spec.whatwg.org/#dom-url-href
  936. defineBuiltInAccessor(URLPrototype, 'href', accessorDescriptor('serialize', 'setHref'));
  937. // `URL.prototype.origin` getter
  938. // https://url.spec.whatwg.org/#dom-url-origin
  939. defineBuiltInAccessor(URLPrototype, 'origin', accessorDescriptor('getOrigin'));
  940. // `URL.prototype.protocol` accessors pair
  941. // https://url.spec.whatwg.org/#dom-url-protocol
  942. defineBuiltInAccessor(URLPrototype, 'protocol', accessorDescriptor('getProtocol', 'setProtocol'));
  943. // `URL.prototype.username` accessors pair
  944. // https://url.spec.whatwg.org/#dom-url-username
  945. defineBuiltInAccessor(URLPrototype, 'username', accessorDescriptor('getUsername', 'setUsername'));
  946. // `URL.prototype.password` accessors pair
  947. // https://url.spec.whatwg.org/#dom-url-password
  948. defineBuiltInAccessor(URLPrototype, 'password', accessorDescriptor('getPassword', 'setPassword'));
  949. // `URL.prototype.host` accessors pair
  950. // https://url.spec.whatwg.org/#dom-url-host
  951. defineBuiltInAccessor(URLPrototype, 'host', accessorDescriptor('getHost', 'setHost'));
  952. // `URL.prototype.hostname` accessors pair
  953. // https://url.spec.whatwg.org/#dom-url-hostname
  954. defineBuiltInAccessor(URLPrototype, 'hostname', accessorDescriptor('getHostname', 'setHostname'));
  955. // `URL.prototype.port` accessors pair
  956. // https://url.spec.whatwg.org/#dom-url-port
  957. defineBuiltInAccessor(URLPrototype, 'port', accessorDescriptor('getPort', 'setPort'));
  958. // `URL.prototype.pathname` accessors pair
  959. // https://url.spec.whatwg.org/#dom-url-pathname
  960. defineBuiltInAccessor(URLPrototype, 'pathname', accessorDescriptor('getPathname', 'setPathname'));
  961. // `URL.prototype.search` accessors pair
  962. // https://url.spec.whatwg.org/#dom-url-search
  963. defineBuiltInAccessor(URLPrototype, 'search', accessorDescriptor('getSearch', 'setSearch'));
  964. // `URL.prototype.searchParams` getter
  965. // https://url.spec.whatwg.org/#dom-url-searchparams
  966. defineBuiltInAccessor(URLPrototype, 'searchParams', accessorDescriptor('getSearchParams'));
  967. // `URL.prototype.hash` accessors pair
  968. // https://url.spec.whatwg.org/#dom-url-hash
  969. defineBuiltInAccessor(URLPrototype, 'hash', accessorDescriptor('getHash', 'setHash'));
  970. }
  971. // `URL.prototype.toJSON` method
  972. // https://url.spec.whatwg.org/#dom-url-tojson
  973. defineBuiltIn(URLPrototype, 'toJSON', function toJSON() {
  974. return getInternalURLState(this).serialize();
  975. }, { enumerable: true });
  976. // `URL.prototype.toString` method
  977. // https://url.spec.whatwg.org/#URL-stringification-behavior
  978. defineBuiltIn(URLPrototype, 'toString', function toString() {
  979. return getInternalURLState(this).serialize();
  980. }, { enumerable: true });
  981. if (NativeURL) {
  982. var nativeCreateObjectURL = NativeURL.createObjectURL;
  983. var nativeRevokeObjectURL = NativeURL.revokeObjectURL;
  984. // `URL.createObjectURL` method
  985. // https://developer.mozilla.org/en-US/docs/Web/API/URL/createObjectURL
  986. if (nativeCreateObjectURL) defineBuiltIn(URLConstructor, 'createObjectURL', bind(nativeCreateObjectURL, NativeURL));
  987. // `URL.revokeObjectURL` method
  988. // https://developer.mozilla.org/en-US/docs/Web/API/URL/revokeObjectURL
  989. if (nativeRevokeObjectURL) defineBuiltIn(URLConstructor, 'revokeObjectURL', bind(nativeRevokeObjectURL, NativeURL));
  990. }
  991. setToStringTag(URLConstructor, 'URL');
  992. $({ global: true, constructor: true, forced: !USE_NATIVE_URL, sham: !DESCRIPTORS }, {
  993. URL: URLConstructor
  994. });