mirror of
https://github.com/avwo/whistle.git
synced 2026-10-18 22:51:32 +08:00
201 lines
4.3 KiB
JavaScript
201 lines
4.3 KiB
JavaScript
var parseUrl = require('url').parse;
|
|
var formatHost = require('./common').formatHost;
|
|
|
|
var CONTROL_RE = /^[\n\r\t\x00-\x20\u00a0\u1680\u2000-\u200a\u2028\u2029\u202f\u205f\u3000\ufeff]+/;
|
|
var PROTOCOL_RE = /^([a-z][a-z0-9.+-]*:)?(\/\/)?([\\/]+)?([\S\s]*)/i;
|
|
var WIN_DRIVE_RE = /^[a-zA-Z]:/;
|
|
var PORT_RE = /:(\d*)$/;
|
|
|
|
function needPort(port, protocol) {
|
|
protocol = protocol.split(':')[0];
|
|
port = +port;
|
|
|
|
if (!port) {
|
|
return false;
|
|
}
|
|
|
|
switch (protocol) {
|
|
case 'http':
|
|
case 'ws':
|
|
return port !== 80;
|
|
|
|
case 'https':
|
|
case 'wss':
|
|
return port !== 443;
|
|
|
|
case 'ftp':
|
|
return port !== 21;
|
|
|
|
case 'gopher':
|
|
return port !== 70;
|
|
|
|
case 'file':
|
|
return false;
|
|
}
|
|
|
|
return port !== 0;
|
|
}
|
|
|
|
function getProtocol(addr) {
|
|
var match = PROTOCOL_RE.exec(addr);
|
|
var protocol = match[1] ? match[1].toLowerCase() : '';
|
|
var forwardSlashes = match[2] || '';
|
|
var otherSlashes = match[3] || '';
|
|
var slashesCount = forwardSlashes.length + otherSlashes.length;
|
|
var rest = forwardSlashes + otherSlashes + match[4];
|
|
|
|
if (protocol === 'file:') {
|
|
if (slashesCount >= 2) {
|
|
rest = rest.slice(2);
|
|
}
|
|
} else if (protocol && forwardSlashes) {
|
|
rest = rest.slice(2);
|
|
}
|
|
|
|
return {
|
|
protocol: protocol,
|
|
slashes: !!forwardSlashes,
|
|
slashesCount: slashesCount,
|
|
rest: rest
|
|
};
|
|
}
|
|
|
|
function encode(str) {
|
|
try {
|
|
return encodeURIComponent(decodeURIComponent(str));
|
|
} catch (e) {
|
|
return '';
|
|
}
|
|
}
|
|
|
|
function formatPath(url) {
|
|
if (url.pathname.charAt(0) !== '/') {
|
|
url.pathname = '/' + url.pathname;
|
|
}
|
|
}
|
|
|
|
function formatPort(url) {
|
|
if (!needPort(url.port, url.protocol)) {
|
|
url.host = url.hostname;
|
|
url.port = '';
|
|
}
|
|
}
|
|
|
|
function parseAuth(url) {
|
|
url.username = url.password = '';
|
|
if (url.auth) {
|
|
var index = url.auth.indexOf(':');
|
|
if (index !== -1) {
|
|
url.username = url.auth.slice(0, index);
|
|
url.username = encode(url.username);
|
|
url.password = url.auth.slice(index + 1);
|
|
url.password = encode(url.password);
|
|
} else {
|
|
url.username = encode(url.auth);
|
|
}
|
|
url.auth = url.password ? url.username +':'+ url.password : url.username;
|
|
}
|
|
}
|
|
|
|
function formatOrigin(url) {
|
|
var protocol = url.protocol;
|
|
if (protocol !== 'file:' && url.host) {
|
|
url.origin = protocol +'//'+ url.host;
|
|
} else {
|
|
url.origin = 'null';
|
|
}
|
|
}
|
|
|
|
function formatUrl(url) {
|
|
var host = url.host;
|
|
var protocol = url.protocol;
|
|
var result = protocol + (protocol && url.slashes ? '//' : '');
|
|
|
|
if (url.username) {
|
|
result += url.username;
|
|
if (url.password) {
|
|
result += ':'+ url.password;
|
|
}
|
|
result += '@';
|
|
} else if (url.password) {
|
|
result += ':'+ url.password + '@';
|
|
}
|
|
|
|
result += host + url.pathname;
|
|
|
|
if (url.search) {
|
|
result += url.search;
|
|
}
|
|
|
|
if (url.hash) {
|
|
result += url.hash;
|
|
}
|
|
url.href = result;
|
|
}
|
|
|
|
module.exports = function(addr) {
|
|
try {
|
|
return parseUrl(addr);
|
|
} catch (e) {}
|
|
|
|
addr = String(addr || '').replace(CONTROL_RE, '');
|
|
|
|
var url = {};
|
|
var result = getProtocol(addr);
|
|
var protocol = result.protocol;
|
|
|
|
url.slashes = result.slashes;
|
|
url.protocol = protocol;
|
|
addr = result.rest;
|
|
|
|
var index = addr.indexOf('#');
|
|
if (index !== -1) {
|
|
url.hash = addr.substring(index);
|
|
addr = addr.substring(0, index);
|
|
}
|
|
|
|
index = addr.indexOf('?');
|
|
if (index !== -1) {
|
|
url.search = addr.substring(index);
|
|
url.query = addr.substring(index + 1);
|
|
addr = addr.substring(0, index);
|
|
}
|
|
|
|
if (
|
|
(protocol === 'file:' && (result.slashesCount !== 2 || WIN_DRIVE_RE.test(addr))) ||
|
|
(!result.slashes && (protocol || result.slashesCount < 2))
|
|
) {
|
|
url.pathname = addr;
|
|
url.host = url.hostname = '';
|
|
} else {
|
|
index = addr.indexOf('/');
|
|
if (index !== -1) {
|
|
url.pathname = addr.substring(index);
|
|
addr = addr.substring(0, index);
|
|
} else {
|
|
url.pathname = '/';
|
|
}
|
|
url.path = url.pathname + (url.search || '');
|
|
index = addr.lastIndexOf('@');
|
|
if (index !== -1) {
|
|
url.auth = addr.substring(0, index);
|
|
addr = addr.substring(index + 1);
|
|
}
|
|
|
|
url.host = addr;
|
|
index = PORT_RE.exec(addr);
|
|
if (index) {
|
|
url.port = index[1];
|
|
addr = addr.substring(0, index.index);
|
|
}
|
|
url.hostname = formatHost(addr);
|
|
}
|
|
|
|
formatPath(url);
|
|
formatPort(url);
|
|
parseAuth(url);
|
|
formatOrigin(url);
|
|
formatUrl(url);
|
|
return url;
|
|
};
|