web.url.constructor.js 36 KB

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