web.url.constructor.js 35 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050
  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 globalThis = require('../internals/global-this');
  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');
  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 = globalThis.URL;
  29. var TypeError = globalThis.TypeError;
  30. var parseInt = globalThis.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. return currLength > maxLength ? currStart : maxIndex;
  198. };
  199. // https://url.spec.whatwg.org/#host-serializing
  200. var serializeHost = function (host) {
  201. var result, index, compress, ignore0;
  202. // ipv4
  203. if (typeof host == 'number') {
  204. result = [];
  205. for (index = 0; index < 4; index++) {
  206. unshift(result, host % 256);
  207. host = floor(host / 256);
  208. }
  209. return join(result, '.');
  210. }
  211. // ipv6
  212. if (typeof host == 'object') {
  213. result = '';
  214. compress = findLongestZeroSequence(host);
  215. for (index = 0; index < 8; index++) {
  216. if (ignore0 && host[index] === 0) continue;
  217. if (ignore0) ignore0 = false;
  218. if (compress === index) {
  219. result += index ? ':' : '::';
  220. ignore0 = true;
  221. } else {
  222. result += numberToString(host[index], 16);
  223. if (index < 7) result += ':';
  224. }
  225. }
  226. return '[' + result + ']';
  227. }
  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 new 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 new 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_C0_CONTROL_OR_SPACE, '');
  339. input = replace(input, TRAILING_C0_CONTROL_OR_SPACE, '$1');
  340. }
  341. input = replace(input, TAB_AND_NEW_LINE, '');
  342. codePoints = arrayFrom(input);
  343. while (pointer <= codePoints.length) {
  344. chr = codePoints[pointer];
  345. switch (state) {
  346. case SCHEME_START:
  347. if (chr && exec(ALPHA, chr)) {
  348. buffer += toLowerCase(chr);
  349. state = SCHEME;
  350. } else if (!stateOverride) {
  351. state = NO_SCHEME;
  352. continue;
  353. } else return INVALID_SCHEME;
  354. break;
  355. case SCHEME:
  356. if (chr && (exec(ALPHANUMERIC, chr) || chr === '+' || chr === '-' || chr === '.')) {
  357. buffer += toLowerCase(chr);
  358. } else if (chr === ':') {
  359. if (stateOverride && (
  360. (url.isSpecial() !== hasOwn(specialSchemes, buffer)) ||
  361. (buffer === 'file' && (url.includesCredentials() || url.port !== null)) ||
  362. (url.scheme === 'file' && !url.host)
  363. )) return;
  364. url.scheme = buffer;
  365. if (stateOverride) {
  366. if (url.isSpecial() && specialSchemes[url.scheme] === url.port) url.port = null;
  367. return;
  368. }
  369. buffer = '';
  370. if (url.scheme === 'file') {
  371. state = FILE;
  372. } else if (url.isSpecial() && base && base.scheme === url.scheme) {
  373. state = SPECIAL_RELATIVE_OR_AUTHORITY;
  374. } else if (url.isSpecial()) {
  375. state = SPECIAL_AUTHORITY_SLASHES;
  376. } else if (codePoints[pointer + 1] === '/') {
  377. state = PATH_OR_AUTHORITY;
  378. pointer++;
  379. } else {
  380. url.cannotBeABaseURL = true;
  381. push(url.path, '');
  382. state = CANNOT_BE_A_BASE_URL_PATH;
  383. }
  384. } else if (!stateOverride) {
  385. buffer = '';
  386. state = NO_SCHEME;
  387. pointer = 0;
  388. continue;
  389. } else return INVALID_SCHEME;
  390. break;
  391. case NO_SCHEME:
  392. if (!base || (base.cannotBeABaseURL && chr !== '#')) return INVALID_SCHEME;
  393. if (base.cannotBeABaseURL && chr === '#') {
  394. url.scheme = base.scheme;
  395. url.path = arraySlice(base.path);
  396. url.query = base.query;
  397. url.fragment = '';
  398. url.cannotBeABaseURL = true;
  399. state = FRAGMENT;
  400. break;
  401. }
  402. state = base.scheme === 'file' ? FILE : RELATIVE;
  403. continue;
  404. case SPECIAL_RELATIVE_OR_AUTHORITY:
  405. if (chr === '/' && codePoints[pointer + 1] === '/') {
  406. state = SPECIAL_AUTHORITY_IGNORE_SLASHES;
  407. pointer++;
  408. } else {
  409. state = RELATIVE;
  410. continue;
  411. } break;
  412. case PATH_OR_AUTHORITY:
  413. if (chr === '/') {
  414. state = AUTHORITY;
  415. break;
  416. } else {
  417. state = PATH;
  418. continue;
  419. }
  420. case RELATIVE:
  421. url.scheme = base.scheme;
  422. if (chr === EOF) {
  423. url.username = base.username;
  424. url.password = base.password;
  425. url.host = base.host;
  426. url.port = base.port;
  427. url.path = arraySlice(base.path);
  428. url.query = base.query;
  429. } else if (chr === '/' || (chr === '\\' && url.isSpecial())) {
  430. state = RELATIVE_SLASH;
  431. } else if (chr === '?') {
  432. url.username = base.username;
  433. url.password = base.password;
  434. url.host = base.host;
  435. url.port = base.port;
  436. url.path = arraySlice(base.path);
  437. url.query = '';
  438. state = QUERY;
  439. } else if (chr === '#') {
  440. url.username = base.username;
  441. url.password = base.password;
  442. url.host = base.host;
  443. url.port = base.port;
  444. url.path = arraySlice(base.path);
  445. url.query = base.query;
  446. url.fragment = '';
  447. state = FRAGMENT;
  448. } else {
  449. url.username = base.username;
  450. url.password = base.password;
  451. url.host = base.host;
  452. url.port = base.port;
  453. url.path = arraySlice(base.path);
  454. url.path.length--;
  455. state = PATH;
  456. continue;
  457. } break;
  458. case RELATIVE_SLASH:
  459. if (url.isSpecial() && (chr === '/' || chr === '\\')) {
  460. state = SPECIAL_AUTHORITY_IGNORE_SLASHES;
  461. } else if (chr === '/') {
  462. state = AUTHORITY;
  463. } else {
  464. url.username = base.username;
  465. url.password = base.password;
  466. url.host = base.host;
  467. url.port = base.port;
  468. state = PATH;
  469. continue;
  470. } break;
  471. case SPECIAL_AUTHORITY_SLASHES:
  472. state = SPECIAL_AUTHORITY_IGNORE_SLASHES;
  473. if (chr !== '/' || charAt(buffer, pointer + 1) !== '/') continue;
  474. pointer++;
  475. break;
  476. case SPECIAL_AUTHORITY_IGNORE_SLASHES:
  477. if (chr !== '/' && chr !== '\\') {
  478. state = AUTHORITY;
  479. continue;
  480. } break;
  481. case AUTHORITY:
  482. if (chr === '@') {
  483. if (seenAt) buffer = '%40' + buffer;
  484. seenAt = true;
  485. bufferCodePoints = arrayFrom(buffer);
  486. for (var i = 0; i < bufferCodePoints.length; i++) {
  487. var codePoint = bufferCodePoints[i];
  488. if (codePoint === ':' && !seenPasswordToken) {
  489. seenPasswordToken = true;
  490. continue;
  491. }
  492. var encodedCodePoints = percentEncode(codePoint, userinfoPercentEncodeSet);
  493. if (seenPasswordToken) url.password += encodedCodePoints;
  494. else url.username += encodedCodePoints;
  495. }
  496. buffer = '';
  497. } else if (
  498. chr === EOF || chr === '/' || chr === '?' || chr === '#' ||
  499. (chr === '\\' && url.isSpecial())
  500. ) {
  501. if (seenAt && buffer === '') return INVALID_AUTHORITY;
  502. pointer -= arrayFrom(buffer).length + 1;
  503. buffer = '';
  504. state = HOST;
  505. } else buffer += chr;
  506. break;
  507. case HOST:
  508. case HOSTNAME:
  509. if (stateOverride && url.scheme === 'file') {
  510. state = FILE_HOST;
  511. continue;
  512. } else if (chr === ':' && !seenBracket) {
  513. if (buffer === '') return INVALID_HOST;
  514. failure = url.parseHost(buffer);
  515. if (failure) return failure;
  516. buffer = '';
  517. state = PORT;
  518. if (stateOverride === HOSTNAME) return;
  519. } else if (
  520. chr === EOF || chr === '/' || chr === '?' || chr === '#' ||
  521. (chr === '\\' && url.isSpecial())
  522. ) {
  523. if (url.isSpecial() && buffer === '') return INVALID_HOST;
  524. if (stateOverride && buffer === '' && (url.includesCredentials() || url.port !== null)) return;
  525. failure = url.parseHost(buffer);
  526. if (failure) return failure;
  527. buffer = '';
  528. state = PATH_START;
  529. if (stateOverride) return;
  530. continue;
  531. } else {
  532. if (chr === '[') seenBracket = true;
  533. else if (chr === ']') seenBracket = false;
  534. buffer += chr;
  535. } break;
  536. case PORT:
  537. if (exec(DIGIT, chr)) {
  538. buffer += chr;
  539. } else if (
  540. chr === EOF || chr === '/' || chr === '?' || chr === '#' ||
  541. (chr === '\\' && url.isSpecial()) ||
  542. stateOverride
  543. ) {
  544. if (buffer !== '') {
  545. var port = parseInt(buffer, 10);
  546. if (port > 0xFFFF) return INVALID_PORT;
  547. url.port = (url.isSpecial() && port === specialSchemes[url.scheme]) ? null : port;
  548. buffer = '';
  549. }
  550. if (stateOverride) return;
  551. state = PATH_START;
  552. continue;
  553. } else return INVALID_PORT;
  554. break;
  555. case FILE:
  556. url.scheme = 'file';
  557. if (chr === '/' || chr === '\\') state = FILE_SLASH;
  558. else if (base && base.scheme === 'file') {
  559. switch (chr) {
  560. case EOF:
  561. url.host = base.host;
  562. url.path = arraySlice(base.path);
  563. url.query = base.query;
  564. break;
  565. case '?':
  566. url.host = base.host;
  567. url.path = arraySlice(base.path);
  568. url.query = '';
  569. state = QUERY;
  570. break;
  571. case '#':
  572. url.host = base.host;
  573. url.path = arraySlice(base.path);
  574. url.query = base.query;
  575. url.fragment = '';
  576. state = FRAGMENT;
  577. break;
  578. default:
  579. if (!startsWithWindowsDriveLetter(join(arraySlice(codePoints, pointer), ''))) {
  580. url.host = base.host;
  581. url.path = arraySlice(base.path);
  582. url.shortenPath();
  583. }
  584. state = PATH;
  585. continue;
  586. }
  587. } else {
  588. state = PATH;
  589. continue;
  590. } break;
  591. case FILE_SLASH:
  592. if (chr === '/' || chr === '\\') {
  593. state = FILE_HOST;
  594. break;
  595. }
  596. if (base && base.scheme === 'file' && !startsWithWindowsDriveLetter(join(arraySlice(codePoints, pointer), ''))) {
  597. if (isWindowsDriveLetter(base.path[0], true)) push(url.path, base.path[0]);
  598. else url.host = base.host;
  599. }
  600. state = PATH;
  601. continue;
  602. case FILE_HOST:
  603. if (chr === EOF || chr === '/' || chr === '\\' || chr === '?' || chr === '#') {
  604. if (!stateOverride && isWindowsDriveLetter(buffer)) {
  605. state = PATH;
  606. } else if (buffer === '') {
  607. url.host = '';
  608. if (stateOverride) return;
  609. state = PATH_START;
  610. } else {
  611. failure = url.parseHost(buffer);
  612. if (failure) return failure;
  613. if (url.host === 'localhost') url.host = '';
  614. if (stateOverride) return;
  615. buffer = '';
  616. state = PATH_START;
  617. } continue;
  618. } else buffer += chr;
  619. break;
  620. case PATH_START:
  621. if (url.isSpecial()) {
  622. state = PATH;
  623. if (chr !== '/' && chr !== '\\') continue;
  624. } else if (!stateOverride && chr === '?') {
  625. url.query = '';
  626. state = QUERY;
  627. } else if (!stateOverride && chr === '#') {
  628. url.fragment = '';
  629. state = FRAGMENT;
  630. } else if (chr !== EOF) {
  631. state = PATH;
  632. if (chr !== '/') continue;
  633. } break;
  634. case PATH:
  635. if (
  636. chr === EOF || chr === '/' ||
  637. (chr === '\\' && url.isSpecial()) ||
  638. (!stateOverride && (chr === '?' || chr === '#'))
  639. ) {
  640. if (isDoubleDot(buffer)) {
  641. url.shortenPath();
  642. if (chr !== '/' && !(chr === '\\' && url.isSpecial())) {
  643. push(url.path, '');
  644. }
  645. } else if (isSingleDot(buffer)) {
  646. if (chr !== '/' && !(chr === '\\' && url.isSpecial())) {
  647. push(url.path, '');
  648. }
  649. } else {
  650. if (url.scheme === 'file' && !url.path.length && isWindowsDriveLetter(buffer)) {
  651. if (url.host) url.host = '';
  652. buffer = charAt(buffer, 0) + ':'; // normalize windows drive letter
  653. }
  654. push(url.path, buffer);
  655. }
  656. buffer = '';
  657. if (url.scheme === 'file' && (chr === EOF || chr === '?' || chr === '#')) {
  658. while (url.path.length > 1 && url.path[0] === '') {
  659. shift(url.path);
  660. }
  661. }
  662. if (chr === '?') {
  663. url.query = '';
  664. state = QUERY;
  665. } else if (chr === '#') {
  666. url.fragment = '';
  667. state = FRAGMENT;
  668. }
  669. } else {
  670. buffer += percentEncode(chr, pathPercentEncodeSet);
  671. } break;
  672. case CANNOT_BE_A_BASE_URL_PATH:
  673. if (chr === '?') {
  674. url.query = '';
  675. state = QUERY;
  676. } else if (chr === '#') {
  677. url.fragment = '';
  678. state = FRAGMENT;
  679. } else if (chr !== EOF) {
  680. url.path[0] += percentEncode(chr, C0ControlPercentEncodeSet);
  681. } break;
  682. case QUERY:
  683. if (!stateOverride && chr === '#') {
  684. url.fragment = '';
  685. state = FRAGMENT;
  686. } else if (chr !== EOF) {
  687. if (chr === "'" && url.isSpecial()) url.query += '%27';
  688. else if (chr === '#') url.query += '%23';
  689. else url.query += percentEncode(chr, C0ControlPercentEncodeSet);
  690. } break;
  691. case FRAGMENT:
  692. if (chr !== EOF) url.fragment += percentEncode(chr, fragmentPercentEncodeSet);
  693. break;
  694. }
  695. pointer++;
  696. }
  697. },
  698. // https://url.spec.whatwg.org/#host-parsing
  699. parseHost: function (input) {
  700. var result, codePoints, index;
  701. if (charAt(input, 0) === '[') {
  702. if (charAt(input, input.length - 1) !== ']') return INVALID_HOST;
  703. result = parseIPv6(stringSlice(input, 1, -1));
  704. if (!result) return INVALID_HOST;
  705. this.host = result;
  706. // opaque host
  707. } else if (!this.isSpecial()) {
  708. if (exec(FORBIDDEN_HOST_CODE_POINT_EXCLUDING_PERCENT, input)) return INVALID_HOST;
  709. result = '';
  710. codePoints = arrayFrom(input);
  711. for (index = 0; index < codePoints.length; index++) {
  712. result += percentEncode(codePoints[index], C0ControlPercentEncodeSet);
  713. }
  714. this.host = result;
  715. } else {
  716. input = toASCII(input);
  717. if (exec(FORBIDDEN_HOST_CODE_POINT, input)) return INVALID_HOST;
  718. result = parseIPv4(input);
  719. if (result === null) return INVALID_HOST;
  720. this.host = result;
  721. }
  722. },
  723. // https://url.spec.whatwg.org/#cannot-have-a-username-password-port
  724. cannotHaveUsernamePasswordPort: function () {
  725. return !this.host || this.cannotBeABaseURL || this.scheme === 'file';
  726. },
  727. // https://url.spec.whatwg.org/#include-credentials
  728. includesCredentials: function () {
  729. return this.username !== '' || this.password !== '';
  730. },
  731. // https://url.spec.whatwg.org/#is-special
  732. isSpecial: function () {
  733. return hasOwn(specialSchemes, this.scheme);
  734. },
  735. // https://url.spec.whatwg.org/#shorten-a-urls-path
  736. shortenPath: function () {
  737. var path = this.path;
  738. var pathSize = path.length;
  739. if (pathSize && (this.scheme !== 'file' || pathSize !== 1 || !isWindowsDriveLetter(path[0], true))) {
  740. path.length--;
  741. }
  742. },
  743. // https://url.spec.whatwg.org/#concept-url-serializer
  744. serialize: function () {
  745. var url = this;
  746. var scheme = url.scheme;
  747. var username = url.username;
  748. var password = url.password;
  749. var host = url.host;
  750. var port = url.port;
  751. var path = url.path;
  752. var query = url.query;
  753. var fragment = url.fragment;
  754. var output = scheme + ':';
  755. if (host !== null) {
  756. output += '//';
  757. if (url.includesCredentials()) {
  758. output += username + (password ? ':' + password : '') + '@';
  759. }
  760. output += serializeHost(host);
  761. if (port !== null) output += ':' + port;
  762. } else if (scheme === 'file') output += '//';
  763. output += url.cannotBeABaseURL ? path[0] : path.length ? '/' + join(path, '/') : '';
  764. if (query !== null) output += '?' + query;
  765. if (fragment !== null) output += '#' + fragment;
  766. return output;
  767. },
  768. // https://url.spec.whatwg.org/#dom-url-href
  769. setHref: function (href) {
  770. var failure = this.parse(href);
  771. if (failure) throw new TypeError(failure);
  772. this.searchParams.update();
  773. },
  774. // https://url.spec.whatwg.org/#dom-url-origin
  775. getOrigin: function () {
  776. var scheme = this.scheme;
  777. var port = this.port;
  778. if (scheme === 'blob') try {
  779. return new URLConstructor(scheme.path[0]).origin;
  780. } catch (error) {
  781. return 'null';
  782. }
  783. if (scheme === 'file' || !this.isSpecial()) return 'null';
  784. return scheme + '://' + serializeHost(this.host) + (port !== null ? ':' + port : '');
  785. },
  786. // https://url.spec.whatwg.org/#dom-url-protocol
  787. getProtocol: function () {
  788. return this.scheme + ':';
  789. },
  790. setProtocol: function (protocol) {
  791. this.parse($toString(protocol) + ':', SCHEME_START);
  792. },
  793. // https://url.spec.whatwg.org/#dom-url-username
  794. getUsername: function () {
  795. return this.username;
  796. },
  797. setUsername: function (username) {
  798. var codePoints = arrayFrom($toString(username));
  799. if (this.cannotHaveUsernamePasswordPort()) return;
  800. this.username = '';
  801. for (var i = 0; i < codePoints.length; i++) {
  802. this.username += percentEncode(codePoints[i], userinfoPercentEncodeSet);
  803. }
  804. },
  805. // https://url.spec.whatwg.org/#dom-url-password
  806. getPassword: function () {
  807. return this.password;
  808. },
  809. setPassword: function (password) {
  810. var codePoints = arrayFrom($toString(password));
  811. if (this.cannotHaveUsernamePasswordPort()) return;
  812. this.password = '';
  813. for (var i = 0; i < codePoints.length; i++) {
  814. this.password += percentEncode(codePoints[i], userinfoPercentEncodeSet);
  815. }
  816. },
  817. // https://url.spec.whatwg.org/#dom-url-host
  818. getHost: function () {
  819. var host = this.host;
  820. var port = this.port;
  821. return host === null ? ''
  822. : port === null ? serializeHost(host)
  823. : serializeHost(host) + ':' + port;
  824. },
  825. setHost: function (host) {
  826. if (this.cannotBeABaseURL) return;
  827. this.parse(host, HOST);
  828. },
  829. // https://url.spec.whatwg.org/#dom-url-hostname
  830. getHostname: function () {
  831. var host = this.host;
  832. return host === null ? '' : serializeHost(host);
  833. },
  834. setHostname: function (hostname) {
  835. if (this.cannotBeABaseURL) return;
  836. this.parse(hostname, HOSTNAME);
  837. },
  838. // https://url.spec.whatwg.org/#dom-url-port
  839. getPort: function () {
  840. var port = this.port;
  841. return port === null ? '' : $toString(port);
  842. },
  843. setPort: function (port) {
  844. if (this.cannotHaveUsernamePasswordPort()) return;
  845. port = $toString(port);
  846. if (port === '') this.port = null;
  847. else this.parse(port, PORT);
  848. },
  849. // https://url.spec.whatwg.org/#dom-url-pathname
  850. getPathname: function () {
  851. var path = this.path;
  852. return this.cannotBeABaseURL ? path[0] : path.length ? '/' + join(path, '/') : '';
  853. },
  854. setPathname: function (pathname) {
  855. if (this.cannotBeABaseURL) return;
  856. this.path = [];
  857. this.parse(pathname, PATH_START);
  858. },
  859. // https://url.spec.whatwg.org/#dom-url-search
  860. getSearch: function () {
  861. var query = this.query;
  862. return query ? '?' + query : '';
  863. },
  864. setSearch: function (search) {
  865. search = $toString(search);
  866. if (search === '') {
  867. this.query = null;
  868. } else {
  869. if (charAt(search, 0) === '?') search = stringSlice(search, 1);
  870. this.query = '';
  871. this.parse(search, QUERY);
  872. }
  873. this.searchParams.update();
  874. },
  875. // https://url.spec.whatwg.org/#dom-url-searchparams
  876. getSearchParams: function () {
  877. return this.searchParams.facade;
  878. },
  879. // https://url.spec.whatwg.org/#dom-url-hash
  880. getHash: function () {
  881. var fragment = this.fragment;
  882. return fragment ? '#' + fragment : '';
  883. },
  884. setHash: function (hash) {
  885. hash = $toString(hash);
  886. if (hash === '') {
  887. this.fragment = null;
  888. return;
  889. }
  890. if (charAt(hash, 0) === '#') hash = stringSlice(hash, 1);
  891. this.fragment = '';
  892. this.parse(hash, FRAGMENT);
  893. },
  894. update: function () {
  895. this.query = this.searchParams.serialize() || null;
  896. }
  897. };
  898. // `URL` constructor
  899. // https://url.spec.whatwg.org/#url-class
  900. var URLConstructor = function URL(url /* , base */) {
  901. var that = anInstance(this, URLPrototype);
  902. var base = validateArgumentsLength(arguments.length, 1) > 1 ? arguments[1] : undefined;
  903. var state = setInternalState(that, new URLState(url, false, base));
  904. if (!DESCRIPTORS) {
  905. that.href = state.serialize();
  906. that.origin = state.getOrigin();
  907. that.protocol = state.getProtocol();
  908. that.username = state.getUsername();
  909. that.password = state.getPassword();
  910. that.host = state.getHost();
  911. that.hostname = state.getHostname();
  912. that.port = state.getPort();
  913. that.pathname = state.getPathname();
  914. that.search = state.getSearch();
  915. that.searchParams = state.getSearchParams();
  916. that.hash = state.getHash();
  917. }
  918. };
  919. var URLPrototype = URLConstructor.prototype;
  920. var accessorDescriptor = function (getter, setter) {
  921. return {
  922. get: function () {
  923. return getInternalURLState(this)[getter]();
  924. },
  925. set: setter && function (value) {
  926. return getInternalURLState(this)[setter](value);
  927. },
  928. configurable: true,
  929. enumerable: true
  930. };
  931. };
  932. if (DESCRIPTORS) {
  933. // `URL.prototype.href` accessors pair
  934. // https://url.spec.whatwg.org/#dom-url-href
  935. defineBuiltInAccessor(URLPrototype, 'href', accessorDescriptor('serialize', 'setHref'));
  936. // `URL.prototype.origin` getter
  937. // https://url.spec.whatwg.org/#dom-url-origin
  938. defineBuiltInAccessor(URLPrototype, 'origin', accessorDescriptor('getOrigin'));
  939. // `URL.prototype.protocol` accessors pair
  940. // https://url.spec.whatwg.org/#dom-url-protocol
  941. defineBuiltInAccessor(URLPrototype, 'protocol', accessorDescriptor('getProtocol', 'setProtocol'));
  942. // `URL.prototype.username` accessors pair
  943. // https://url.spec.whatwg.org/#dom-url-username
  944. defineBuiltInAccessor(URLPrototype, 'username', accessorDescriptor('getUsername', 'setUsername'));
  945. // `URL.prototype.password` accessors pair
  946. // https://url.spec.whatwg.org/#dom-url-password
  947. defineBuiltInAccessor(URLPrototype, 'password', accessorDescriptor('getPassword', 'setPassword'));
  948. // `URL.prototype.host` accessors pair
  949. // https://url.spec.whatwg.org/#dom-url-host
  950. defineBuiltInAccessor(URLPrototype, 'host', accessorDescriptor('getHost', 'setHost'));
  951. // `URL.prototype.hostname` accessors pair
  952. // https://url.spec.whatwg.org/#dom-url-hostname
  953. defineBuiltInAccessor(URLPrototype, 'hostname', accessorDescriptor('getHostname', 'setHostname'));
  954. // `URL.prototype.port` accessors pair
  955. // https://url.spec.whatwg.org/#dom-url-port
  956. defineBuiltInAccessor(URLPrototype, 'port', accessorDescriptor('getPort', 'setPort'));
  957. // `URL.prototype.pathname` accessors pair
  958. // https://url.spec.whatwg.org/#dom-url-pathname
  959. defineBuiltInAccessor(URLPrototype, 'pathname', accessorDescriptor('getPathname', 'setPathname'));
  960. // `URL.prototype.search` accessors pair
  961. // https://url.spec.whatwg.org/#dom-url-search
  962. defineBuiltInAccessor(URLPrototype, 'search', accessorDescriptor('getSearch', 'setSearch'));
  963. // `URL.prototype.searchParams` getter
  964. // https://url.spec.whatwg.org/#dom-url-searchparams
  965. defineBuiltInAccessor(URLPrototype, 'searchParams', accessorDescriptor('getSearchParams'));
  966. // `URL.prototype.hash` accessors pair
  967. // https://url.spec.whatwg.org/#dom-url-hash
  968. defineBuiltInAccessor(URLPrototype, 'hash', accessorDescriptor('getHash', 'setHash'));
  969. }
  970. // `URL.prototype.toJSON` method
  971. // https://url.spec.whatwg.org/#dom-url-tojson
  972. defineBuiltIn(URLPrototype, 'toJSON', function toJSON() {
  973. return getInternalURLState(this).serialize();
  974. }, { enumerable: true });
  975. // `URL.prototype.toString` method
  976. // https://url.spec.whatwg.org/#URL-stringification-behavior
  977. defineBuiltIn(URLPrototype, 'toString', function toString() {
  978. return getInternalURLState(this).serialize();
  979. }, { enumerable: true });
  980. if (NativeURL) {
  981. var nativeCreateObjectURL = NativeURL.createObjectURL;
  982. var nativeRevokeObjectURL = NativeURL.revokeObjectURL;
  983. // `URL.createObjectURL` method
  984. // https://developer.mozilla.org/en-US/docs/Web/API/URL/createObjectURL
  985. if (nativeCreateObjectURL) defineBuiltIn(URLConstructor, 'createObjectURL', bind(nativeCreateObjectURL, NativeURL));
  986. // `URL.revokeObjectURL` method
  987. // https://developer.mozilla.org/en-US/docs/Web/API/URL/revokeObjectURL
  988. if (nativeRevokeObjectURL) defineBuiltIn(URLConstructor, 'revokeObjectURL', bind(nativeRevokeObjectURL, NativeURL));
  989. }
  990. setToStringTag(URLConstructor, 'URL');
  991. $({ global: true, constructor: true, forced: !USE_NATIVE_URL, sham: !DESCRIPTORS }, {
  992. URL: URLConstructor
  993. });