url-parse.js 21 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756
  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){(function (){
  3. 'use strict';
  4. var required = require('requires-port')
  5. , qs = require('querystringify')
  6. , controlOrWhitespace = /^[\x00-\x20\u00a0\u1680\u2000-\u200a\u2028\u2029\u202f\u205f\u3000\ufeff]+/
  7. , CRHTLF = /[\n\r\t]/g
  8. , slashes = /^[A-Za-z][A-Za-z0-9+-.]*:\/\//
  9. , port = /:\d+$/
  10. , protocolre = /^([a-z][a-z0-9.+-]*:)?(\/\/)?([\\/]+)?([\S\s]*)/i
  11. , windowsDriveLetter = /^[a-zA-Z]:/;
  12. /**
  13. * Remove control characters and whitespace from the beginning of a string.
  14. *
  15. * @param {Object|String} str String to trim.
  16. * @returns {String} A new string representing `str` stripped of control
  17. * characters and whitespace from its beginning.
  18. * @public
  19. */
  20. function trimLeft(str) {
  21. return (str ? str : '').toString().replace(controlOrWhitespace, '');
  22. }
  23. /**
  24. * These are the parse rules for the URL parser, it informs the parser
  25. * about:
  26. *
  27. * 0. The char it Needs to parse, if it's a string it should be done using
  28. * indexOf, RegExp using exec and NaN means set as current value.
  29. * 1. The property we should set when parsing this value.
  30. * 2. Indication if it's backwards or forward parsing, when set as number it's
  31. * the value of extra chars that should be split off.
  32. * 3. Inherit from location if non existing in the parser.
  33. * 4. `toLowerCase` the resulting value.
  34. */
  35. var rules = [
  36. ['#', 'hash'], // Extract from the back.
  37. ['?', 'query'], // Extract from the back.
  38. function sanitize(address, url) { // Sanitize what is left of the address
  39. return isSpecial(url.protocol) ? address.replace(/\\/g, '/') : address;
  40. },
  41. ['/', 'pathname'], // Extract from the back.
  42. ['@', 'auth', 1], // Extract from the front.
  43. [NaN, 'host', undefined, 1, 1], // Set left over value.
  44. [/:(\d*)$/, 'port', undefined, 1], // RegExp the back.
  45. [NaN, 'hostname', undefined, 1, 1] // Set left over.
  46. ];
  47. /**
  48. * These properties should not be copied or inherited from. This is only needed
  49. * for all non blob URL's as a blob URL does not include a hash, only the
  50. * origin.
  51. *
  52. * @type {Object}
  53. * @private
  54. */
  55. var ignore = { hash: 1, query: 1 };
  56. /**
  57. * The location object differs when your code is loaded through a normal page,
  58. * Worker or through a worker using a blob. And with the blobble begins the
  59. * trouble as the location object will contain the URL of the blob, not the
  60. * location of the page where our code is loaded in. The actual origin is
  61. * encoded in the `pathname` so we can thankfully generate a good "default"
  62. * location from it so we can generate proper relative URL's again.
  63. *
  64. * @param {Object|String} loc Optional default location object.
  65. * @returns {Object} lolcation object.
  66. * @public
  67. */
  68. function lolcation(loc) {
  69. var globalVar;
  70. if (typeof window !== 'undefined') globalVar = window;
  71. else if (typeof global !== 'undefined') globalVar = global;
  72. else if (typeof self !== 'undefined') globalVar = self;
  73. else globalVar = {};
  74. var location = globalVar.location || {};
  75. loc = loc || location;
  76. var finaldestination = {}
  77. , type = typeof loc
  78. , key;
  79. if ('blob:' === loc.protocol) {
  80. finaldestination = new Url(unescape(loc.pathname), {});
  81. } else if ('string' === type) {
  82. finaldestination = new Url(loc, {});
  83. for (key in ignore) delete finaldestination[key];
  84. } else if ('object' === type) {
  85. for (key in loc) {
  86. if (key in ignore) continue;
  87. finaldestination[key] = loc[key];
  88. }
  89. if (finaldestination.slashes === undefined) {
  90. finaldestination.slashes = slashes.test(loc.href);
  91. }
  92. }
  93. return finaldestination;
  94. }
  95. /**
  96. * Check whether a protocol scheme is special.
  97. *
  98. * @param {String} The protocol scheme of the URL
  99. * @return {Boolean} `true` if the protocol scheme is special, else `false`
  100. * @private
  101. */
  102. function isSpecial(scheme) {
  103. return (
  104. scheme === 'file:' ||
  105. scheme === 'ftp:' ||
  106. scheme === 'http:' ||
  107. scheme === 'https:' ||
  108. scheme === 'ws:' ||
  109. scheme === 'wss:'
  110. );
  111. }
  112. /**
  113. * @typedef ProtocolExtract
  114. * @type Object
  115. * @property {String} protocol Protocol matched in the URL, in lowercase.
  116. * @property {Boolean} slashes `true` if protocol is followed by "//", else `false`.
  117. * @property {String} rest Rest of the URL that is not part of the protocol.
  118. */
  119. /**
  120. * Extract protocol information from a URL with/without double slash ("//").
  121. *
  122. * @param {String} address URL we want to extract from.
  123. * @param {Object} location
  124. * @return {ProtocolExtract} Extracted information.
  125. * @private
  126. */
  127. function extractProtocol(address, location) {
  128. address = trimLeft(address);
  129. address = address.replace(CRHTLF, '');
  130. location = location || {};
  131. var match = protocolre.exec(address);
  132. var protocol = match[1] ? match[1].toLowerCase() : '';
  133. var forwardSlashes = !!match[2];
  134. var otherSlashes = !!match[3];
  135. var slashesCount = 0;
  136. var rest;
  137. if (forwardSlashes) {
  138. if (otherSlashes) {
  139. rest = match[2] + match[3] + match[4];
  140. slashesCount = match[2].length + match[3].length;
  141. } else {
  142. rest = match[2] + match[4];
  143. slashesCount = match[2].length;
  144. }
  145. } else {
  146. if (otherSlashes) {
  147. rest = match[3] + match[4];
  148. slashesCount = match[3].length;
  149. } else {
  150. rest = match[4]
  151. }
  152. }
  153. if (protocol === 'file:') {
  154. if (slashesCount >= 2) {
  155. rest = rest.slice(2);
  156. }
  157. } else if (isSpecial(protocol)) {
  158. rest = match[4];
  159. } else if (protocol) {
  160. if (forwardSlashes) {
  161. rest = rest.slice(2);
  162. }
  163. } else if (slashesCount >= 2 && isSpecial(location.protocol)) {
  164. rest = match[4];
  165. }
  166. return {
  167. protocol: protocol,
  168. slashes: forwardSlashes || isSpecial(protocol),
  169. slashesCount: slashesCount,
  170. rest: rest
  171. };
  172. }
  173. /**
  174. * Resolve a relative URL pathname against a base URL pathname.
  175. *
  176. * @param {String} relative Pathname of the relative URL.
  177. * @param {String} base Pathname of the base URL.
  178. * @return {String} Resolved pathname.
  179. * @private
  180. */
  181. function resolve(relative, base) {
  182. if (relative === '') return base;
  183. var path = (base || '/').split('/').slice(0, -1).concat(relative.split('/'))
  184. , i = path.length
  185. , last = path[i - 1]
  186. , unshift = false
  187. , up = 0;
  188. while (i--) {
  189. if (path[i] === '.') {
  190. path.splice(i, 1);
  191. } else if (path[i] === '..') {
  192. path.splice(i, 1);
  193. up++;
  194. } else if (up) {
  195. if (i === 0) unshift = true;
  196. path.splice(i, 1);
  197. up--;
  198. }
  199. }
  200. if (unshift) path.unshift('');
  201. if (last === '.' || last === '..') path.push('');
  202. return path.join('/');
  203. }
  204. /**
  205. * The actual URL instance. Instead of returning an object we've opted-in to
  206. * create an actual constructor as it's much more memory efficient and
  207. * faster and it pleases my OCD.
  208. *
  209. * It is worth noting that we should not use `URL` as class name to prevent
  210. * clashes with the global URL instance that got introduced in browsers.
  211. *
  212. * @constructor
  213. * @param {String} address URL we want to parse.
  214. * @param {Object|String} [location] Location defaults for relative paths.
  215. * @param {Boolean|Function} [parser] Parser for the query string.
  216. * @private
  217. */
  218. function Url(address, location, parser) {
  219. address = trimLeft(address);
  220. address = address.replace(CRHTLF, '');
  221. if (!(this instanceof Url)) {
  222. return new Url(address, location, parser);
  223. }
  224. var relative, extracted, parse, instruction, index, key
  225. , instructions = rules.slice()
  226. , type = typeof location
  227. , url = this
  228. , i = 0;
  229. //
  230. // The following if statements allows this module two have compatibility with
  231. // 2 different API:
  232. //
  233. // 1. Node.js's `url.parse` api which accepts a URL, boolean as arguments
  234. // where the boolean indicates that the query string should also be parsed.
  235. //
  236. // 2. The `URL` interface of the browser which accepts a URL, object as
  237. // arguments. The supplied object will be used as default values / fall-back
  238. // for relative paths.
  239. //
  240. if ('object' !== type && 'string' !== type) {
  241. parser = location;
  242. location = null;
  243. }
  244. if (parser && 'function' !== typeof parser) parser = qs.parse;
  245. location = lolcation(location);
  246. //
  247. // Extract protocol information before running the instructions.
  248. //
  249. extracted = extractProtocol(address || '', location);
  250. relative = !extracted.protocol && !extracted.slashes;
  251. url.slashes = extracted.slashes || relative && location.slashes;
  252. url.protocol = extracted.protocol || location.protocol || '';
  253. address = extracted.rest;
  254. //
  255. // When the authority component is absent the URL starts with a path
  256. // component.
  257. //
  258. if (
  259. extracted.protocol === 'file:' && (
  260. extracted.slashesCount !== 2 || windowsDriveLetter.test(address)) ||
  261. (!extracted.slashes &&
  262. (extracted.protocol ||
  263. extracted.slashesCount < 2 ||
  264. !isSpecial(url.protocol)))
  265. ) {
  266. instructions[3] = [/(.*)/, 'pathname'];
  267. }
  268. for (; i < instructions.length; i++) {
  269. instruction = instructions[i];
  270. if (typeof instruction === 'function') {
  271. address = instruction(address, url);
  272. continue;
  273. }
  274. parse = instruction[0];
  275. key = instruction[1];
  276. if (parse !== parse) {
  277. url[key] = address;
  278. } else if ('string' === typeof parse) {
  279. index = parse === '@'
  280. ? address.lastIndexOf(parse)
  281. : address.indexOf(parse);
  282. if (~index) {
  283. if ('number' === typeof instruction[2]) {
  284. url[key] = address.slice(0, index);
  285. address = address.slice(index + instruction[2]);
  286. } else {
  287. url[key] = address.slice(index);
  288. address = address.slice(0, index);
  289. }
  290. }
  291. } else if ((index = parse.exec(address))) {
  292. url[key] = index[1];
  293. address = address.slice(0, index.index);
  294. }
  295. url[key] = url[key] || (
  296. relative && instruction[3] ? location[key] || '' : ''
  297. );
  298. //
  299. // Hostname, host and protocol should be lowercased so they can be used to
  300. // create a proper `origin`.
  301. //
  302. if (instruction[4]) url[key] = url[key].toLowerCase();
  303. }
  304. //
  305. // Also parse the supplied query string in to an object. If we're supplied
  306. // with a custom parser as function use that instead of the default build-in
  307. // parser.
  308. //
  309. if (parser) url.query = parser(url.query);
  310. //
  311. // If the URL is relative, resolve the pathname against the base URL.
  312. //
  313. if (
  314. relative
  315. && location.slashes
  316. && url.pathname.charAt(0) !== '/'
  317. && (url.pathname !== '' || location.pathname !== '')
  318. ) {
  319. url.pathname = resolve(url.pathname, location.pathname);
  320. }
  321. //
  322. // Default to a / for pathname if none exists. This normalizes the URL
  323. // to always have a /
  324. //
  325. if (url.pathname.charAt(0) !== '/' && isSpecial(url.protocol)) {
  326. url.pathname = '/' + url.pathname;
  327. }
  328. //
  329. // We should not add port numbers if they are already the default port number
  330. // for a given protocol. As the host also contains the port number we're going
  331. // override it with the hostname which contains no port number.
  332. //
  333. if (!required(url.port, url.protocol)) {
  334. url.host = url.hostname;
  335. url.port = '';
  336. }
  337. //
  338. // Parse down the `auth` for the username and password.
  339. //
  340. url.username = url.password = '';
  341. if (url.auth) {
  342. index = url.auth.indexOf(':');
  343. if (~index) {
  344. url.username = url.auth.slice(0, index);
  345. url.username = encodeURIComponent(decodeURIComponent(url.username));
  346. url.password = url.auth.slice(index + 1);
  347. url.password = encodeURIComponent(decodeURIComponent(url.password))
  348. } else {
  349. url.username = encodeURIComponent(decodeURIComponent(url.auth));
  350. }
  351. url.auth = url.password ? url.username +':'+ url.password : url.username;
  352. }
  353. url.origin = url.protocol !== 'file:' && isSpecial(url.protocol) && url.host
  354. ? url.protocol +'//'+ url.host
  355. : 'null';
  356. //
  357. // The href is just the compiled result.
  358. //
  359. url.href = url.toString();
  360. }
  361. /**
  362. * This is convenience method for changing properties in the URL instance to
  363. * insure that they all propagate correctly.
  364. *
  365. * @param {String} part Property we need to adjust.
  366. * @param {Mixed} value The newly assigned value.
  367. * @param {Boolean|Function} fn When setting the query, it will be the function
  368. * used to parse the query.
  369. * When setting the protocol, double slash will be
  370. * removed from the final url if it is true.
  371. * @returns {URL} URL instance for chaining.
  372. * @public
  373. */
  374. function set(part, value, fn) {
  375. var url = this;
  376. switch (part) {
  377. case 'query':
  378. if ('string' === typeof value && value.length) {
  379. value = (fn || qs.parse)(value);
  380. }
  381. url[part] = value;
  382. break;
  383. case 'port':
  384. url[part] = value;
  385. if (!required(value, url.protocol)) {
  386. url.host = url.hostname;
  387. url[part] = '';
  388. } else if (value) {
  389. url.host = url.hostname +':'+ value;
  390. }
  391. break;
  392. case 'hostname':
  393. url[part] = value;
  394. if (url.port) value += ':'+ url.port;
  395. url.host = value;
  396. break;
  397. case 'host':
  398. url[part] = value;
  399. if (port.test(value)) {
  400. value = value.split(':');
  401. url.port = value.pop();
  402. url.hostname = value.join(':');
  403. } else {
  404. url.hostname = value;
  405. url.port = '';
  406. }
  407. break;
  408. case 'protocol':
  409. url.protocol = value.toLowerCase();
  410. url.slashes = !fn;
  411. break;
  412. case 'pathname':
  413. case 'hash':
  414. if (value) {
  415. var char = part === 'pathname' ? '/' : '#';
  416. url[part] = value.charAt(0) !== char ? char + value : value;
  417. } else {
  418. url[part] = value;
  419. }
  420. break;
  421. case 'username':
  422. case 'password':
  423. url[part] = encodeURIComponent(value);
  424. break;
  425. case 'auth':
  426. var index = value.indexOf(':');
  427. if (~index) {
  428. url.username = value.slice(0, index);
  429. url.username = encodeURIComponent(decodeURIComponent(url.username));
  430. url.password = value.slice(index + 1);
  431. url.password = encodeURIComponent(decodeURIComponent(url.password));
  432. } else {
  433. url.username = encodeURIComponent(decodeURIComponent(value));
  434. }
  435. }
  436. for (var i = 0; i < rules.length; i++) {
  437. var ins = rules[i];
  438. if (ins[4]) url[ins[1]] = url[ins[1]].toLowerCase();
  439. }
  440. url.auth = url.password ? url.username +':'+ url.password : url.username;
  441. url.origin = url.protocol !== 'file:' && isSpecial(url.protocol) && url.host
  442. ? url.protocol +'//'+ url.host
  443. : 'null';
  444. url.href = url.toString();
  445. return url;
  446. }
  447. /**
  448. * Transform the properties back in to a valid and full URL string.
  449. *
  450. * @param {Function} stringify Optional query stringify function.
  451. * @returns {String} Compiled version of the URL.
  452. * @public
  453. */
  454. function toString(stringify) {
  455. if (!stringify || 'function' !== typeof stringify) stringify = qs.stringify;
  456. var query
  457. , url = this
  458. , host = url.host
  459. , protocol = url.protocol;
  460. if (protocol && protocol.charAt(protocol.length - 1) !== ':') protocol += ':';
  461. var result =
  462. protocol +
  463. ((url.protocol && url.slashes) || isSpecial(url.protocol) ? '//' : '');
  464. if (url.username) {
  465. result += url.username;
  466. if (url.password) result += ':'+ url.password;
  467. result += '@';
  468. } else if (url.password) {
  469. result += ':'+ url.password;
  470. result += '@';
  471. } else if (
  472. url.protocol !== 'file:' &&
  473. isSpecial(url.protocol) &&
  474. !host &&
  475. url.pathname !== '/'
  476. ) {
  477. //
  478. // Add back the empty userinfo, otherwise the original invalid URL
  479. // might be transformed into a valid one with `url.pathname` as host.
  480. //
  481. result += '@';
  482. }
  483. //
  484. // Trailing colon is removed from `url.host` when it is parsed. If it still
  485. // ends with a colon, then add back the trailing colon that was removed. This
  486. // prevents an invalid URL from being transformed into a valid one.
  487. //
  488. if (host[host.length - 1] === ':' || (port.test(url.hostname) && !url.port)) {
  489. host += ':';
  490. }
  491. result += host + url.pathname;
  492. query = 'object' === typeof url.query ? stringify(url.query) : url.query;
  493. if (query) result += '?' !== query.charAt(0) ? '?'+ query : query;
  494. if (url.hash) result += url.hash;
  495. return result;
  496. }
  497. Url.prototype = { set: set, toString: toString };
  498. //
  499. // Expose the URL parser and some additional properties that might be useful for
  500. // others or testing.
  501. //
  502. Url.extractProtocol = extractProtocol;
  503. Url.location = lolcation;
  504. Url.trimLeft = trimLeft;
  505. Url.qs = qs;
  506. module.exports = Url;
  507. }).call(this)}).call(this,typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {})
  508. },{"querystringify":2,"requires-port":3}],2:[function(require,module,exports){
  509. 'use strict';
  510. var has = Object.prototype.hasOwnProperty
  511. , undef;
  512. /**
  513. * Decode a URI encoded string.
  514. *
  515. * @param {String} input The URI encoded string.
  516. * @returns {String|Null} The decoded string.
  517. * @api private
  518. */
  519. function decode(input) {
  520. try {
  521. return decodeURIComponent(input.replace(/\+/g, ' '));
  522. } catch (e) {
  523. return null;
  524. }
  525. }
  526. /**
  527. * Attempts to encode a given input.
  528. *
  529. * @param {String} input The string that needs to be encoded.
  530. * @returns {String|Null} The encoded string.
  531. * @api private
  532. */
  533. function encode(input) {
  534. try {
  535. return encodeURIComponent(input);
  536. } catch (e) {
  537. return null;
  538. }
  539. }
  540. /**
  541. * Simple query string parser.
  542. *
  543. * @param {String} query The query string that needs to be parsed.
  544. * @returns {Object}
  545. * @api public
  546. */
  547. function querystring(query) {
  548. var parser = /([^=?#&]+)=?([^&]*)/g
  549. , result = {}
  550. , part;
  551. while (part = parser.exec(query)) {
  552. var key = decode(part[1])
  553. , value = decode(part[2]);
  554. //
  555. // Prevent overriding of existing properties. This ensures that build-in
  556. // methods like `toString` or __proto__ are not overriden by malicious
  557. // querystrings.
  558. //
  559. // In the case if failed decoding, we want to omit the key/value pairs
  560. // from the result.
  561. //
  562. if (key === null || value === null || key in result) continue;
  563. result[key] = value;
  564. }
  565. return result;
  566. }
  567. /**
  568. * Transform a query string to an object.
  569. *
  570. * @param {Object} obj Object that should be transformed.
  571. * @param {String} prefix Optional prefix.
  572. * @returns {String}
  573. * @api public
  574. */
  575. function querystringify(obj, prefix) {
  576. prefix = prefix || '';
  577. var pairs = []
  578. , value
  579. , key;
  580. //
  581. // Optionally prefix with a '?' if needed
  582. //
  583. if ('string' !== typeof prefix) prefix = '?';
  584. for (key in obj) {
  585. if (has.call(obj, key)) {
  586. value = obj[key];
  587. //
  588. // Edge cases where we actually want to encode the value to an empty
  589. // string instead of the stringified value.
  590. //
  591. if (!value && (value === null || value === undef || isNaN(value))) {
  592. value = '';
  593. }
  594. key = encode(key);
  595. value = encode(value);
  596. //
  597. // If we failed to encode the strings, we should bail out as we don't
  598. // want to add invalid strings to the query.
  599. //
  600. if (key === null || value === null) continue;
  601. pairs.push(key +'='+ value);
  602. }
  603. }
  604. return pairs.length ? prefix + pairs.join('&') : '';
  605. }
  606. //
  607. // Expose the module.
  608. //
  609. exports.stringify = querystringify;
  610. exports.parse = querystring;
  611. },{}],3:[function(require,module,exports){
  612. 'use strict';
  613. /**
  614. * Check if we're required to add a port number.
  615. *
  616. * @see https://url.spec.whatwg.org/#default-port
  617. * @param {Number|String} port Port number we need to check
  618. * @param {String} protocol Protocol we need to check against.
  619. * @returns {Boolean} Is it a default port for the given protocol
  620. * @api private
  621. */
  622. module.exports = function required(port, protocol) {
  623. protocol = protocol.split(':')[0];
  624. port = +port;
  625. if (!port) return false;
  626. switch (protocol) {
  627. case 'http':
  628. case 'ws':
  629. return port !== 80;
  630. case 'https':
  631. case 'wss':
  632. return port !== 443;
  633. case 'ftp':
  634. return port !== 21;
  635. case 'gopher':
  636. return port !== 70;
  637. case 'file':
  638. return false;
  639. }
  640. return port !== 0;
  641. };
  642. },{}]},{},[1])(1)
  643. });