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.

573 lines
16 KiB

4 years ago
  1. (function(f){if(typeof exports==="object"&&typeof module!=="undefined"){module.exports=f()}else if(typeof define==="function"&&define.amd){define([],f)}else{var g;if(typeof window!=="undefined"){g=window}else if(typeof global!=="undefined"){g=global}else if(typeof self!=="undefined"){g=self}else{g=this}g.URLParse = f()}})(function(){var define,module,exports;return (function(){function r(e,n,t){function o(i,f){if(!n[i]){if(!e[i]){var c="function"==typeof require&&require;if(!f&&c)return c(i,!0);if(u)return u(i,!0);var a=new Error("Cannot find module '"+i+"'");throw a.code="MODULE_NOT_FOUND",a}var p=n[i]={exports:{}};e[i][0].call(p.exports,function(r){var n=e[i][1][r];return o(n||r)},p,p.exports,r,e,n,t)}return n[i].exports}for(var u="function"==typeof require&&require,i=0;i<t.length;i++)o(t[i]);return o}return r})()({1:[function(require,module,exports){
  2. (function (global){
  3. 'use strict';
  4. var required = require('requires-port')
  5. , qs = require('querystringify')
  6. , slashes = /^[A-Za-z][A-Za-z0-9+-.]*:\/\//
  7. , protocolre = /^([a-z][a-z0-9.+-]*:)?(\/\/)?([\S\s]*)/i
  8. , whitespace = '[\\x09\\x0A\\x0B\\x0C\\x0D\\x20\\xA0\\u1680\\u180E\\u2000\\u2001\\u2002\\u2003\\u2004\\u2005\\u2006\\u2007\\u2008\\u2009\\u200A\\u202F\\u205F\\u3000\\u2028\\u2029\\uFEFF]'
  9. , left = new RegExp('^'+ whitespace +'+');
  10. /**
  11. * Trim a given string.
  12. *
  13. * @param {String} str String to trim.
  14. * @public
  15. */
  16. function trimLeft(str) {
  17. return (str ? str : '').toString().replace(left, '');
  18. }
  19. /**
  20. * These are the parse rules for the URL parser, it informs the parser
  21. * about:
  22. *
  23. * 0. The char it Needs to parse, if it's a string it should be done using
  24. * indexOf, RegExp using exec and NaN means set as current value.
  25. * 1. The property we should set when parsing this value.
  26. * 2. Indication if it's backwards or forward parsing, when set as number it's
  27. * the value of extra chars that should be split off.
  28. * 3. Inherit from location if non existing in the parser.
  29. * 4. `toLowerCase` the resulting value.
  30. */
  31. var rules = [
  32. ['#', 'hash'], // Extract from the back.
  33. ['?', 'query'], // Extract from the back.
  34. function sanitize(address) { // Sanitize what is left of the address
  35. return address.replace('\\', '/');
  36. },
  37. ['/', 'pathname'], // Extract from the back.
  38. ['@', 'auth', 1], // Extract from the front.
  39. [NaN, 'host', undefined, 1, 1], // Set left over value.
  40. [/:(\d+)$/, 'port', undefined, 1], // RegExp the back.
  41. [NaN, 'hostname', undefined, 1, 1] // Set left over.
  42. ];
  43. /**
  44. * These properties should not be copied or inherited from. This is only needed
  45. * for all non blob URL's as a blob URL does not include a hash, only the
  46. * origin.
  47. *
  48. * @type {Object}
  49. * @private
  50. */
  51. var ignore = { hash: 1, query: 1 };
  52. /**
  53. * The location object differs when your code is loaded through a normal page,
  54. * Worker or through a worker using a blob. And with the blobble begins the
  55. * trouble as the location object will contain the URL of the blob, not the
  56. * location of the page where our code is loaded in. The actual origin is
  57. * encoded in the `pathname` so we can thankfully generate a good "default"
  58. * location from it so we can generate proper relative URL's again.
  59. *
  60. * @param {Object|String} loc Optional default location object.
  61. * @returns {Object} lolcation object.
  62. * @public
  63. */
  64. function lolcation(loc) {
  65. var globalVar;
  66. if (typeof window !== 'undefined') globalVar = window;
  67. else if (typeof global !== 'undefined') globalVar = global;
  68. else if (typeof self !== 'undefined') globalVar = self;
  69. else globalVar = {};
  70. var location = globalVar.location || {};
  71. loc = loc || location;
  72. var finaldestination = {}
  73. , type = typeof loc
  74. , key;
  75. if ('blob:' === loc.protocol) {
  76. finaldestination = new Url(unescape(loc.pathname), {});
  77. } else if ('string' === type) {
  78. finaldestination = new Url(loc, {});
  79. for (key in ignore) delete finaldestination[key];
  80. } else if ('object' === type) {
  81. for (key in loc) {
  82. if (key in ignore) continue;
  83. finaldestination[key] = loc[key];
  84. }
  85. if (finaldestination.slashes === undefined) {
  86. finaldestination.slashes = slashes.test(loc.href);
  87. }
  88. }
  89. return finaldestination;
  90. }
  91. /**
  92. * @typedef ProtocolExtract
  93. * @type Object
  94. * @property {String} protocol Protocol matched in the URL, in lowercase.
  95. * @property {Boolean} slashes `true` if protocol is followed by "//", else `false`.
  96. * @property {String} rest Rest of the URL that is not part of the protocol.
  97. */
  98. /**
  99. * Extract protocol information from a URL with/without double slash ("//").
  100. *
  101. * @param {String} address URL we want to extract from.
  102. * @return {ProtocolExtract} Extracted information.
  103. * @private
  104. */
  105. function extractProtocol(address) {
  106. address = trimLeft(address);
  107. var match = protocolre.exec(address);
  108. return {
  109. protocol: match[1] ? match[1].toLowerCase() : '',
  110. slashes: !!match[2],
  111. rest: match[3]
  112. };
  113. }
  114. /**
  115. * Resolve a relative URL pathname against a base URL pathname.
  116. *
  117. * @param {String} relative Pathname of the relative URL.
  118. * @param {String} base Pathname of the base URL.
  119. * @return {String} Resolved pathname.
  120. * @private
  121. */
  122. function resolve(relative, base) {
  123. if (relative === '') return base;
  124. var path = (base || '/').split('/').slice(0, -1).concat(relative.split('/'))
  125. , i = path.length
  126. , last = path[i - 1]
  127. , unshift = false
  128. , up = 0;
  129. while (i--) {
  130. if (path[i] === '.') {
  131. path.splice(i, 1);
  132. } else if (path[i] === '..') {
  133. path.splice(i, 1);
  134. up++;
  135. } else if (up) {
  136. if (i === 0) unshift = true;
  137. path.splice(i, 1);
  138. up--;
  139. }
  140. }
  141. if (unshift) path.unshift('');
  142. if (last === '.' || last === '..') path.push('');
  143. return path.join('/');
  144. }
  145. /**
  146. * The actual URL instance. Instead of returning an object we've opted-in to
  147. * create an actual constructor as it's much more memory efficient and
  148. * faster and it pleases my OCD.
  149. *
  150. * It is worth noting that we should not use `URL` as class name to prevent
  151. * clashes with the global URL instance that got introduced in browsers.
  152. *
  153. * @constructor
  154. * @param {String} address URL we want to parse.
  155. * @param {Object|String} [location] Location defaults for relative paths.
  156. * @param {Boolean|Function} [parser] Parser for the query string.
  157. * @private
  158. */
  159. function Url(address, location, parser) {
  160. address = trimLeft(address);
  161. if (!(this instanceof Url)) {
  162. return new Url(address, location, parser);
  163. }
  164. var relative, extracted, parse, instruction, index, key
  165. , instructions = rules.slice()
  166. , type = typeof location
  167. , url = this
  168. , i = 0;
  169. //
  170. // The following if statements allows this module two have compatibility with
  171. // 2 different API:
  172. //
  173. // 1. Node.js's `url.parse` api which accepts a URL, boolean as arguments
  174. // where the boolean indicates that the query string should also be parsed.
  175. //
  176. // 2. The `URL` interface of the browser which accepts a URL, object as
  177. // arguments. The supplied object will be used as default values / fall-back
  178. // for relative paths.
  179. //
  180. if ('object' !== type && 'string' !== type) {
  181. parser = location;
  182. location = null;
  183. }
  184. if (parser && 'function' !== typeof parser) parser = qs.parse;
  185. location = lolcation(location);
  186. //
  187. // Extract protocol information before running the instructions.
  188. //
  189. extracted = extractProtocol(address || '');
  190. relative = !extracted.protocol && !extracted.slashes;
  191. url.slashes = extracted.slashes || relative && location.slashes;
  192. url.protocol = extracted.protocol || location.protocol || '';
  193. address = extracted.rest;
  194. //
  195. // When the authority component is absent the URL starts with a path
  196. // component.
  197. //
  198. if (!extracted.slashes) instructions[3] = [/(.*)/, 'pathname'];
  199. for (; i < instructions.length; i++) {
  200. instruction = instructions[i];
  201. if (typeof instruction === 'function') {
  202. address = instruction(address);
  203. continue;
  204. }
  205. parse = instruction[0];
  206. key = instruction[1];
  207. if (parse !== parse) {
  208. url[key] = address;
  209. } else if ('string' === typeof parse) {
  210. if (~(index = address.indexOf(parse))) {
  211. if ('number' === typeof instruction[2]) {
  212. url[key] = address.slice(0, index);
  213. address = address.slice(index + instruction[2]);
  214. } else {
  215. url[key] = address.slice(index);
  216. address = address.slice(0, index);
  217. }
  218. }
  219. } else if ((index = parse.exec(address))) {
  220. url[key] = index[1];
  221. address = address.slice(0, index.index);
  222. }
  223. url[key] = url[key] || (
  224. relative && instruction[3] ? location[key] || '' : ''
  225. );
  226. //
  227. // Hostname, host and protocol should be lowercased so they can be used to
  228. // create a proper `origin`.
  229. //
  230. if (instruction[4]) url[key] = url[key].toLowerCase();
  231. }
  232. //
  233. // Also parse the supplied query string in to an object. If we're supplied
  234. // with a custom parser as function use that instead of the default build-in
  235. // parser.
  236. //
  237. if (parser) url.query = parser(url.query);
  238. //
  239. // If the URL is relative, resolve the pathname against the base URL.
  240. //
  241. if (
  242. relative
  243. && location.slashes
  244. && url.pathname.charAt(0) !== '/'
  245. && (url.pathname !== '' || location.pathname !== '')
  246. ) {
  247. url.pathname = resolve(url.pathname, location.pathname);
  248. }
  249. //
  250. // We should not add port numbers if they are already the default port number
  251. // for a given protocol. As the host also contains the port number we're going
  252. // override it with the hostname which contains no port number.
  253. //
  254. if (!required(url.port, url.protocol)) {
  255. url.host = url.hostname;
  256. url.port = '';
  257. }
  258. //
  259. // Parse down the `auth` for the username and password.
  260. //
  261. url.username = url.password = '';
  262. if (url.auth) {
  263. instruction = url.auth.split(':');
  264. url.username = instruction[0] || '';
  265. url.password = instruction[1] || '';
  266. }
  267. url.origin = url.protocol && url.host && url.protocol !== 'file:'
  268. ? url.protocol +'//'+ url.host
  269. : 'null';
  270. //
  271. // The href is just the compiled result.
  272. //
  273. url.href = url.toString();
  274. }
  275. /**
  276. * This is convenience method for changing properties in the URL instance to
  277. * insure that they all propagate correctly.
  278. *
  279. * @param {String} part Property we need to adjust.
  280. * @param {Mixed} value The newly assigned value.
  281. * @param {Boolean|Function} fn When setting the query, it will be the function
  282. * used to parse the query.
  283. * When setting the protocol, double slash will be
  284. * removed from the final url if it is true.
  285. * @returns {URL} URL instance for chaining.
  286. * @public
  287. */
  288. function set(part, value, fn) {
  289. var url = this;
  290. switch (part) {
  291. case 'query':
  292. if ('string' === typeof value && value.length) {
  293. value = (fn || qs.parse)(value);
  294. }
  295. url[part] = value;
  296. break;
  297. case 'port':
  298. url[part] = value;
  299. if (!required(value, url.protocol)) {
  300. url.host = url.hostname;
  301. url[part] = '';
  302. } else if (value) {
  303. url.host = url.hostname +':'+ value;
  304. }
  305. break;
  306. case 'hostname':
  307. url[part] = value;
  308. if (url.port) value += ':'+ url.port;
  309. url.host = value;
  310. break;
  311. case 'host':
  312. url[part] = value;
  313. if (/:\d+$/.test(value)) {
  314. value = value.split(':');
  315. url.port = value.pop();
  316. url.hostname = value.join(':');
  317. } else {
  318. url.hostname = value;
  319. url.port = '';
  320. }
  321. break;
  322. case 'protocol':
  323. url.protocol = value.toLowerCase();
  324. url.slashes = !fn;
  325. break;
  326. case 'pathname':
  327. case 'hash':
  328. if (value) {
  329. var char = part === 'pathname' ? '/' : '#';
  330. url[part] = value.charAt(0) !== char ? char + value : value;
  331. } else {
  332. url[part] = value;
  333. }
  334. break;
  335. default:
  336. url[part] = value;
  337. }
  338. for (var i = 0; i < rules.length; i++) {
  339. var ins = rules[i];
  340. if (ins[4]) url[ins[1]] = url[ins[1]].toLowerCase();
  341. }
  342. url.origin = url.protocol && url.host && url.protocol !== 'file:'
  343. ? url.protocol +'//'+ url.host
  344. : 'null';
  345. url.href = url.toString();
  346. return url;
  347. }
  348. /**
  349. * Transform the properties back in to a valid and full URL string.
  350. *
  351. * @param {Function} stringify Optional query stringify function.
  352. * @returns {String} Compiled version of the URL.
  353. * @public
  354. */
  355. function toString(stringify) {
  356. if (!stringify || 'function' !== typeof stringify) stringify = qs.stringify;
  357. var query
  358. , url = this
  359. , protocol = url.protocol;
  360. if (protocol && protocol.charAt(protocol.length - 1) !== ':') protocol += ':';
  361. var result = protocol + (url.slashes ? '//' : '');
  362. if (url.username) {
  363. result += url.username;
  364. if (url.password) result += ':'+ url.password;
  365. result += '@';
  366. }
  367. result += url.host + url.pathname;
  368. query = 'object' === typeof url.query ? stringify(url.query) : url.query;
  369. if (query) result += '?' !== query.charAt(0) ? '?'+ query : query;
  370. if (url.hash) result += url.hash;
  371. return result;
  372. }
  373. Url.prototype = { set: set, toString: toString };
  374. //
  375. // Expose the URL parser and some additional properties that might be useful for
  376. // others or testing.
  377. //
  378. Url.extractProtocol = extractProtocol;
  379. Url.location = lolcation;
  380. Url.trimLeft = trimLeft;
  381. Url.qs = qs;
  382. module.exports = Url;
  383. }).call(this,typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {})
  384. },{"querystringify":2,"requires-port":3}],2:[function(require,module,exports){
  385. 'use strict';
  386. var has = Object.prototype.hasOwnProperty;
  387. /**
  388. * Decode a URI encoded string.
  389. *
  390. * @param {String} input The URI encoded string.
  391. * @returns {String} The decoded string.
  392. * @api private
  393. */
  394. function decode(input) {
  395. return decodeURIComponent(input.replace(/\+/g, ' '));
  396. }
  397. /**
  398. * Simple query string parser.
  399. *
  400. * @param {String} query The query string that needs to be parsed.
  401. * @returns {Object}
  402. * @api public
  403. */
  404. function querystring(query) {
  405. var parser = /([^=?&]+)=?([^&]*)/g
  406. , result = {}
  407. , part;
  408. while (part = parser.exec(query)) {
  409. var key = decode(part[1])
  410. , value = decode(part[2]);
  411. //
  412. // Prevent overriding of existing properties. This ensures that build-in
  413. // methods like `toString` or __proto__ are not overriden by malicious
  414. // querystrings.
  415. //
  416. if (key in result) continue;
  417. result[key] = value;
  418. }
  419. return result;
  420. }
  421. /**
  422. * Transform a query string to an object.
  423. *
  424. * @param {Object} obj Object that should be transformed.
  425. * @param {String} prefix Optional prefix.
  426. * @returns {String}
  427. * @api public
  428. */
  429. function querystringify(obj, prefix) {
  430. prefix = prefix || '';
  431. var pairs = [];
  432. //
  433. // Optionally prefix with a '?' if needed
  434. //
  435. if ('string' !== typeof prefix) prefix = '?';
  436. for (var key in obj) {
  437. if (has.call(obj, key)) {
  438. pairs.push(encodeURIComponent(key) +'='+ encodeURIComponent(obj[key]));
  439. }
  440. }
  441. return pairs.length ? prefix + pairs.join('&') : '';
  442. }
  443. //
  444. // Expose the module.
  445. //
  446. exports.stringify = querystringify;
  447. exports.parse = querystring;
  448. },{}],3:[function(require,module,exports){
  449. 'use strict';
  450. /**
  451. * Check if we're required to add a port number.
  452. *
  453. * @see https://url.spec.whatwg.org/#default-port
  454. * @param {Number|String} port Port number we need to check
  455. * @param {String} protocol Protocol we need to check against.
  456. * @returns {Boolean} Is it a default port for the given protocol
  457. * @api private
  458. */
  459. module.exports = function required(port, protocol) {
  460. protocol = protocol.split(':')[0];
  461. port = +port;
  462. if (!port) return false;
  463. switch (protocol) {
  464. case 'http':
  465. case 'ws':
  466. return port !== 80;
  467. case 'https':
  468. case 'wss':
  469. return port !== 443;
  470. case 'ftp':
  471. return port !== 21;
  472. case 'gopher':
  473. return port !== 70;
  474. case 'file':
  475. return false;
  476. }
  477. return port !== 0;
  478. };
  479. },{}]},{},[1])(1)
  480. });