web.url.constructor.js 35 KB

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