web 3d图形渲染器
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

1005 lines
32 KiB

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