web.url.js 34 KB

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