"use strict";
function Url() {
this._protocol = null;
this._href = "";
this._port = -1;
this._query = null;
this.auth = null;
this.slashes = null;
this.host = null;
this.hostname = null;
this.hash = null;
this.search = null;
this.pathname = null;
this._prependSlash = false;
}
var querystring = require("querystring");
Url.queryString = querystring;
Url.prototype.parse =
function Url$parse(str, parseQueryString, hostDenotesSlash, disableAutoEscapeChars) {
if (typeof str !== "string") {
throw new TypeError("Parameter 'url' must be a string, not " +
typeof str);
}
var start = 0;
var end = str.length - 1;
while (str.charCodeAt(start) <= 0x20 ) start++;
while (str.charCodeAt(end) <= 0x20 ) end--;
start = this._parseProtocol(str, start, end);
if (this._protocol !== "javascript") {
start = this._parseHost(str, start, end, hostDenotesSlash);
var proto = this._protocol;
if (!this.hostname &&
(this.slashes || (proto && !slashProtocols[proto]))) {
this.hostname = this.host = "";
}
}
if (start <= end) {
var ch = str.charCodeAt(start);
if (ch === 0x2F || ch === 0x5C ) {
this._parsePath(str, start, end, disableAutoEscapeChars);
}
else if (ch === 0x3F ) {
this._parseQuery(str, start, end, disableAutoEscapeChars);
}
else if (ch === 0x23 ) {
this._parseHash(str, start, end, disableAutoEscapeChars);
}
else if (this._protocol !== "javascript") {
this._parsePath(str, start, end, disableAutoEscapeChars);
}
else { this.pathname = str.slice(start, end + 1 );
}
}
if (!this.pathname && this.hostname &&
this._slashProtocols[this._protocol]) {
this.pathname = "/";
}
if (parseQueryString) {
var search = this.search;
if (search == null) {
search = this.search = "";
}
if (search.charCodeAt(0) === 0x3F ) {
search = search.slice(1);
}
this.query = Url.queryString.parse(search);
}
};
Url.prototype.resolve = function Url$resolve(relative) {
return this.resolveObject(Url.parse(relative, false, true)).format();
};
Url.prototype.format = function Url$format() {
var auth = this.auth || "";
if (auth) {
auth = encodeURIComponent(auth);
auth = auth.replace(/%3A/i, ":");
auth += "@";
}
var protocol = this.protocol || "";
var pathname = this.pathname || "";
var hash = this.hash || "";
var search = this.search || "";
var query = "";
var hostname = this.hostname || "";
var port = this.port || "";
var host = false;
var scheme = "";
var q = this.query;
if (q && typeof q === "object") {
query = Url.queryString.stringify(q);
}
if (!search) {
search = query ? "?" + query : "";
}
if (protocol && protocol.charCodeAt(protocol.length - 1) !== 0x3A )
protocol += ":";
if (this.host) {
host = auth + this.host;
}
else if (hostname) {
var ip6 = hostname.indexOf(":") > -1;
if (ip6) hostname = "[" + hostname + "]";
host = auth + hostname + (port ? ":" + port : "");
}
var slashes = this.slashes ||
((!protocol ||
slashProtocols[protocol]) && host !== false);
if (protocol) scheme = protocol + (slashes ? "//" : "");
else if (slashes) scheme = "//";
if (slashes && pathname && pathname.charCodeAt(0) !== 0x2F ) {
pathname = "/" + pathname;
}
if (search && search.charCodeAt(0) !== 0x3F )
search = "?" + search;
if (hash && hash.charCodeAt(0) !== 0x23 )
hash = "#" + hash;
pathname = escapePathName(pathname);
search = escapeSearch(search);
return scheme + (host === false ? "" : host) + pathname + search + hash;
};
Url.prototype.resolveObject = function Url$resolveObject(relative) {
if (typeof relative === "string")
relative = Url.parse(relative, false, true);
var result = this._clone();
result.hash = relative.hash;
if (!relative.href) {
result._href = "";
return result;
}
if (relative.slashes && !relative._protocol) {
relative._copyPropsTo(result, true);
if (slashProtocols[result._protocol] &&
result.hostname && !result.pathname) {
result.pathname = "/";
}
result._href = "";
return result;
}
if (relative._protocol && relative._protocol !== result._protocol) {
if (!slashProtocols[relative._protocol]) {
relative._copyPropsTo(result, false);
result._href = "";
return result;
}
result._protocol = relative._protocol;
if (!relative.host && relative._protocol !== "javascript") {
var relPath = (relative.pathname || "").split("/");
while (relPath.length && !(relative.host = relPath.shift()));
if (!relative.host) relative.host = "";
if (!relative.hostname) relative.hostname = "";
if (relPath[0] !== "") relPath.unshift("");
if (relPath.length < 2) relPath.unshift("");
result.pathname = relPath.join("/");
} else {
result.pathname = relative.pathname;
}
result.search = relative.search;
result.host = relative.host || "";
result.auth = relative.auth;
result.hostname = relative.hostname || relative.host;
result._port = relative._port;
result.slashes = result.slashes || relative.slashes;
result._href = "";
return result;
}
var isSourceAbs =
(result.pathname && result.pathname.charCodeAt(0) === 0x2F );
var isRelAbs = (
relative.host ||
(relative.pathname &&
relative.pathname.charCodeAt(0) === 0x2F )
);
var mustEndAbs = (isRelAbs || isSourceAbs ||
(result.host && relative.pathname));
var removeAllDots = mustEndAbs;
var srcPath = result.pathname && result.pathname.split("/") || [];
var relPath = relative.pathname && relative.pathname.split("/") || [];
var psychotic = result._protocol && !slashProtocols[result._protocol];
if (psychotic) {
result.hostname = "";
result._port = -1;
if (result.host) {
if (srcPath[0] === "") srcPath[0] = result.host;
else srcPath.unshift(result.host);
}
result.host = "";
if (relative._protocol) {
relative.hostname = "";
relative._port = -1;
if (relative.host) {
if (relPath[0] === "") relPath[0] = relative.host;
else relPath.unshift(relative.host);
}
relative.host = "";
}
mustEndAbs = mustEndAbs && (relPath[0] === "" || srcPath[0] === "");
}
if (isRelAbs) {
result.host = relative.host ?
relative.host : result.host;
result.hostname = relative.hostname ?
relative.hostname : result.hostname;
result.search = relative.search;
srcPath = relPath;
} else if (relPath.length) {
if (!srcPath) srcPath = [];
srcPath.pop();
srcPath = srcPath.concat(relPath);
result.search = relative.search;
} else if (relative.search) {
if (psychotic) {
result.hostname = result.host = srcPath.shift();
var authInHost = result.host && result.host.indexOf("@") > 0 ?
result.host.split("@") : false;
if (authInHost) {
result.auth = authInHost.shift();
result.host = result.hostname = authInHost.shift();
}
}
result.search = relative.search;
result._href = "";
return result;
}
if (!srcPath.length) {
result.pathname = null;
result._href = "";
return result;
}
var last = srcPath.slice(-1)[0];
var hasTrailingSlash = (
(result.host || relative.host) && (last === "." || last === "..") ||
last === "");
var up = 0;
for (var i = srcPath.length; i >= 0; i--) {
last = srcPath[i];
if (last === ".") {
srcPath.splice(i, 1);
} else if (last === "..") {
srcPath.splice(i, 1);
up++;
} else if (up) {
srcPath.splice(i, 1);
up--;
}
}
if (!mustEndAbs && !removeAllDots) {
for (; up--; up) {
srcPath.unshift("..");
}
}
if (mustEndAbs && srcPath[0] !== "" &&
(!srcPath[0] || srcPath[0].charCodeAt(0) !== 0x2F )) {
srcPath.unshift("");
}
if (hasTrailingSlash && (srcPath.join("/").substr(-1) !== "/")) {
srcPath.push("");
}
var isAbsolute = srcPath[0] === "" ||
(srcPath[0] && srcPath[0].charCodeAt(0) === 0x2F );
if (psychotic) {
result.hostname = result.host = isAbsolute ? "" :
srcPath.length ? srcPath.shift() : "";
var authInHost = result.host && result.host.indexOf("@") > 0 ?
result.host.split("@") : false;
if (authInHost) {
result.auth = authInHost.shift();
result.host = result.hostname = authInHost.shift();
}
}
mustEndAbs = mustEndAbs || (result.host && srcPath.length);
if (mustEndAbs && !isAbsolute) {
srcPath.unshift("");
}
result.pathname = srcPath.length === 0 ? null : srcPath.join("/");
result.auth = relative.auth || result.auth;
result.slashes = result.slashes || relative.slashes;
result._href = "";
return result;
};
var punycode = require("punycode");
Url.prototype._hostIdna = function Url$_hostIdna(hostname) {
return punycode.toASCII(hostname);
};
var escapePathName = Url.prototype._escapePathName =
function Url$_escapePathName(pathname) {
if (!containsCharacter2(pathname, 0x23 , 0x3F )) {
return pathname;
}
return _escapePath(pathname);
};
var escapeSearch = Url.prototype._escapeSearch =
function Url$_escapeSearch(search) {
if (!containsCharacter2(search, 0x23 , -1)) return search;
return _escapeSearch(search);
};
Url.prototype._parseProtocol = function Url$_parseProtocol(str, start, end) {
var doLowerCase = false;
var protocolCharacters = this._protocolCharacters;
for (var i = start; i <= end; ++i) {
var ch = str.charCodeAt(i);
if (ch === 0x3A ) {
var protocol = str.slice(start, i);
if (doLowerCase) protocol = protocol.toLowerCase();
this._protocol = protocol;
return i + 1;
}
else if (protocolCharacters[ch] === 1) {
if (ch < 0x61 )
doLowerCase = true;
}
else {
return start;
}
}
return start;
};
Url.prototype._parseAuth = function Url$_parseAuth(str, start, end, decode) {
var auth = str.slice(start, end + 1);
if (decode) {
auth = decodeURIComponent(auth);
}
this.auth = auth;
};
Url.prototype._parsePort = function Url$_parsePort(str, start, end) {
var port = 0;
var hadChars = false;
var validPort = true;
for (var i = start; i <= end; ++i) {
var ch = str.charCodeAt(i);
if (0x30 <= ch && ch <= 0x39 ) {
port = (10 * port) + (ch - 0x30 );
hadChars = true;
}
else {
validPort = false;
if (ch === 0x5C || ch === 0x2F) {
validPort = true;
}
break;
}
}
if ((port === 0 && !hadChars) || !validPort) {
if (!validPort) {
this._port = -2;
}
return 0;
}
this._port = port;
return i - start;
};
Url.prototype._parseHost =
function Url$_parseHost(str, start, end, slashesDenoteHost) {
var hostEndingCharacters = this._hostEndingCharacters;
var first = str.charCodeAt(start);
var second = str.charCodeAt(start + 1);
if ((first === 0x2F || first === 0x5C ) &&
(second === 0x2F || second === 0x5C )) {
this.slashes = true;
if (start === 0) {
if (end < 2) return start;
var hasAuth =
containsCharacter(str, 0x40 , 2, hostEndingCharacters);
if (!hasAuth && !slashesDenoteHost) {
this.slashes = null;
return start;
}
}
start += 2;
}
else if (!this._protocol ||
slashProtocols[this._protocol]
) {
return start;
}
var doLowerCase = false;
var idna = false;
var hostNameStart = start;
var hostNameEnd = end;
var lastCh = -1;
var portLength = 0;
var charsAfterDot = 0;
var authNeedsDecoding = false;
var j = -1;
for (var i = start; i <= end; ++i) {
var ch = str.charCodeAt(i);
if (ch === 0x40 ) {
j = i;
}
else if (ch === 0x25 ) {
authNeedsDecoding = true;
}
else if (hostEndingCharacters[ch] === 1) {
break;
}
}
if (j > -1) {
this._parseAuth(str, start, j - 1, authNeedsDecoding);
start = hostNameStart = j + 1;
}
if (str.charCodeAt(start) === 0x5B ) {
for (var i = start + 1; i <= end; ++i) {
var ch = str.charCodeAt(i);
if (ch === 0x5D ) {
if (str.charCodeAt(i + 1) === 0x3A ) {
portLength = this._parsePort(str, i + 2, end) + 1;
}
var hostname = str.slice(start + 1, i).toLowerCase();
this.hostname = hostname;
this.host = this._port > 0 ?
"[" + hostname + "]:" + this._port :
"[" + hostname + "]";
this.pathname = "/";
return i + portLength + 1;
}
}
return start;
}
for (var i = start; i <= end; ++i) {
if (charsAfterDot > 62) {
this.hostname = this.host = str.slice(start, i);
return i;
}
var ch = str.charCodeAt(i);
if (ch === 0x3A ) {
portLength = this._parsePort(str, i + 1, end) + 1;
hostNameEnd = i - 1;
break;
}
else if (ch < 0x61 ) {
if (ch === 0x2E ) {
charsAfterDot = -1;
}
else if (0x41 <= ch && ch <= 0x5A ) {
doLowerCase = true;
}
else if (!(ch === 0x2D ||
ch === 0x5F ||
ch === 0x2B ||
(0x30 <= ch && ch <= 0x39 ))
) {
if (hostEndingCharacters[ch] === 0 &&
this._noPrependSlashHostEnders[ch] === 0) {
this._prependSlash = true;
}
hostNameEnd = i - 1;
break;
}
}
else if (ch >= 0x7B ) {
if (ch <= 0x7E ) {
if (this._noPrependSlashHostEnders[ch] === 0) {
this._prependSlash = true;
}
hostNameEnd = i - 1;
break;
}
idna = true;
}
lastCh = ch;
charsAfterDot++;
}
if (hostNameEnd + 1 !== start &&
hostNameEnd - hostNameStart <= 256) {
var hostname = str.slice(hostNameStart, hostNameEnd + 1);
if (doLowerCase) hostname = hostname.toLowerCase();
if (idna) hostname = this._hostIdna(hostname);
this.hostname = hostname;
this.host = this._port > 0 ? hostname + ":" + this._port : hostname;
}
return hostNameEnd + 1 + portLength;
};
Url.prototype._copyPropsTo = function Url$_copyPropsTo(input, noProtocol) {
if (!noProtocol) {
input._protocol = this._protocol;
}
input._href = this._href;
input._port = this._port;
input._prependSlash = this._prependSlash;
input.auth = this.auth;
input.slashes = this.slashes;
input.host = this.host;
input.hostname = this.hostname;
input.hash = this.hash;
input.search = this.search;
input.pathname = this.pathname;
};
Url.prototype._clone = function Url$_clone() {
var ret = new Url();
ret._protocol = this._protocol;
ret._href = this._href;
ret._port = this._port;
ret._prependSlash = this._prependSlash;
ret.auth = this.auth;
ret.slashes = this.slashes;
ret.host = this.host;
ret.hostname = this.hostname;
ret.hash = this.hash;
ret.search = this.search;
ret.pathname = this.pathname;
return ret;
};
Url.prototype._getComponentEscaped =
function Url$_getComponentEscaped(str, start, end, isAfterQuery) {
var cur = start;
var i = start;
var ret = "";
var autoEscapeMap = isAfterQuery ?
this._afterQueryAutoEscapeMap : this._autoEscapeMap;
for (; i <= end; ++i) {
var ch = str.charCodeAt(i);
var escaped = autoEscapeMap[ch];
if (escaped !== "" && escaped !== undefined) {
if (cur < i) ret += str.slice(cur, i);
ret += escaped;
cur = i + 1;
}
}
if (cur < i + 1) ret += str.slice(cur, i);
return ret;
};
Url.prototype._parsePath =
function Url$_parsePath(str, start, end, disableAutoEscapeChars) {
var pathStart = start;
var pathEnd = end;
var escape = false;
var autoEscapeCharacters = this._autoEscapeCharacters;
var prePath = this._port === -2 ? "/:" : "";
for (var i = start; i <= end; ++i) {
var ch = str.charCodeAt(i);
if (ch === 0x23 ) {
this._parseHash(str, i, end, disableAutoEscapeChars);
pathEnd = i - 1;
break;
}
else if (ch === 0x3F ) {
this._parseQuery(str, i, end, disableAutoEscapeChars);
pathEnd = i - 1;
break;
}
else if (!disableAutoEscapeChars && !escape && autoEscapeCharacters[ch] === 1) {
escape = true;
}
}
if (pathStart > pathEnd) {
this.pathname = prePath === "" ? "/" : prePath;
return;
}
var path;
if (escape) {
path = this._getComponentEscaped(str, pathStart, pathEnd, false);
}
else {
path = str.slice(pathStart, pathEnd + 1);
}
this.pathname = prePath === ""
? (this._prependSlash ? "/" + path : path)
: prePath + path;
};
Url.prototype._parseQuery = function Url$_parseQuery(str, start, end, disableAutoEscapeChars) {
var queryStart = start;
var queryEnd = end;
var escape = false;
var autoEscapeCharacters = this._autoEscapeCharacters;
for (var i = start; i <= end; ++i) {
var ch = str.charCodeAt(i);
if (ch === 0x23 ) {
this._parseHash(str, i, end, disableAutoEscapeChars);
queryEnd = i - 1;
break;
}
else if (!disableAutoEscapeChars && !escape && autoEscapeCharacters[ch] === 1) {
escape = true;
}
}
if (queryStart > queryEnd) {
this.search = "";
return;
}
var query;
if (escape) {
query = this._getComponentEscaped(str, queryStart, queryEnd, true);
}
else {
query = str.slice(queryStart, queryEnd + 1);
}
this.search = query;
};
Url.prototype._parseHash = function Url$_parseHash(str, start, end, disableAutoEscapeChars) {
if (start > end) {
this.hash = "";
return;
}
this.hash = disableAutoEscapeChars ?
str.slice(start, end + 1) : this._getComponentEscaped(str, start, end, true);
};
Object.defineProperty(Url.prototype, "port", {
get: function() {
if (this._port >= 0) {
return ("" + this._port);
}
return null;
},
set: function(v) {
if (v == null) {
this._port = -1;
}
else {
this._port = parseInt(v, 10);
}
}
});
Object.defineProperty(Url.prototype, "query", {
get: function() {
var query = this._query;
if (query != null) {
return query;
}
var search = this.search;
if (search) {
if (search.charCodeAt(0) === 0x3F ) {
search = search.slice(1);
}
if (search !== "") {
this._query = search;
return search;
}
}
return search;
},
set: function(v) {
this._query = v;
}
});
Object.defineProperty(Url.prototype, "path", {
get: function() {
var p = this.pathname || "";
var s = this.search || "";
if (p || s) {
return p + s;
}
return (p == null && s) ? ("/" + s) : null;
},
set: function() {}
});
Object.defineProperty(Url.prototype, "protocol", {
get: function() {
var proto = this._protocol;
return proto ? proto + ":" : proto;
},
set: function(v) {
if (typeof v === "string") {
var end = v.length - 1;
if (v.charCodeAt(end) === 0x3A ) {
this._protocol = v.slice(0, end);
}
else {
this._protocol = v;
}
}
else if (v == null) {
this._protocol = null;
}
}
});
Object.defineProperty(Url.prototype, "href", {
get: function() {
var href = this._href;
if (!href) {
href = this._href = this.format();
}
return href;
},
set: function(v) {
this._href = v;
}
});
Url.parse = function Url$Parse(str, parseQueryString, hostDenotesSlash, disableAutoEscapeChars) {
if (str instanceof Url) return str;
var ret = new Url();
ret.parse(str, !!parseQueryString, !!hostDenotesSlash, !!disableAutoEscapeChars);
return ret;
};
Url.format = function Url$Format(obj) {
if (typeof obj === "string") {
obj = Url.parse(obj);
}
if (!(obj instanceof Url)) {
return Url.prototype.format.call(obj);
}
return obj.format();
};
Url.resolve = function Url$Resolve(source, relative) {
return Url.parse(source, false, true).resolve(relative);
};
Url.resolveObject = function Url$ResolveObject(source, relative) {
if (!source) return relative;
return Url.parse(source, false, true).resolveObject(relative);
};
function _escapePath(pathname) {
return pathname.replace(/[?#]/g, function(match) {
return encodeURIComponent(match);
});
}
function _escapeSearch(search) {
return search.replace(/#/g, function(match) {
return encodeURIComponent(match);
});
}
function containsCharacter(string, char1, fromIndex, stopCharacterTable) {
var len = string.length;
for (var i = fromIndex; i < len; ++i) {
var ch = string.charCodeAt(i);
if (ch === char1) {
return true;
}
else if (stopCharacterTable[ch] === 1) {
return false;
}
}
return false;
}
function containsCharacter2(string, char1, char2) {
for (var i = 0, len = string.length; i < len; ++i) {
var ch = string.charCodeAt(i);
if (ch === char1 || ch === char2) return true;
}
return false;
}
function makeAsciiTable(spec) {
var ret = new Uint8Array(128);
spec.forEach(function(item){
if (typeof item === "number") {
ret[item] = 1;
}
else {
var start = item[0];
var end = item[1];
for (var j = start; j <= end; ++j) {
ret[j] = 1;
}
}
});
return ret;
}
var autoEscape = ["<", ">", "\"", "`", " ", "\r", "\n",
"\t", "{", "}", "|", "\\", "^", "`", "'"];
var autoEscapeMap = new Array(128);
for (var i = 0, len = autoEscapeMap.length; i < len; ++i) {
autoEscapeMap[i] = "";
}
for (var i = 0, len = autoEscape.length; i < len; ++i) {
var c = autoEscape[i];
var esc = encodeURIComponent(c);
if (esc === c) {
esc = escape(c);
}
autoEscapeMap[c.charCodeAt(0)] = esc;
}
var afterQueryAutoEscapeMap = autoEscapeMap.slice();
autoEscapeMap[0x5C ] = "/";
var slashProtocols = Url.prototype._slashProtocols = {
http: true,
https: true,
gopher: true,
file: true,
ftp: true,
"http:": true,
"https:": true,
"gopher:": true,
"file:": true,
"ftp:": true
};
function f(){}
f.prototype = slashProtocols;
Url.prototype._protocolCharacters = makeAsciiTable([
[0x61 , 0x7A ],
[0x41 , 0x5A ],
0x2E , 0x2B , 0x2D
]);
Url.prototype._hostEndingCharacters = makeAsciiTable([
0x23 , 0x3F , 0x2F , 0x5C
]);
Url.prototype._autoEscapeCharacters = makeAsciiTable(
autoEscape.map(function(v) {
return v.charCodeAt(0);
})
);
Url.prototype._noPrependSlashHostEnders = makeAsciiTable(
[
"<", ">", "'", "`", " ", "\r",
"\n", "\t", "{", "}", "|",
"^", "`", "\"", "%", ";"
].map(function(v) {
return v.charCodeAt(0);
})
);
Url.prototype._autoEscapeMap = autoEscapeMap;
Url.prototype._afterQueryAutoEscapeMap = afterQueryAutoEscapeMap;
module.exports = Url;
Url.replace = function Url$Replace() {
require.cache.url = {
exports: Url
};
};