aboutsummaryrefslogtreecommitdiff
path: root/lib/url.js
diff options
context:
space:
mode:
Diffstat (limited to 'lib/url.js')
-rw-r--r--lib/url.js73
1 files changed, 51 insertions, 22 deletions
diff --git a/lib/url.js b/lib/url.js
index d5948e450b..4c0ef0102f 100644
--- a/lib/url.js
+++ b/lib/url.js
@@ -20,6 +20,7 @@
// USE OR OTHER DEALINGS IN THE SOFTWARE.
var punycode = require('punycode');
+var util = require('util');
exports.parse = urlParse;
exports.resolve = urlResolve;
@@ -50,21 +51,23 @@ function Url() {
var protocolPattern = /^([a-z0-9.+-]+:)/i,
portPattern = /:[0-9]*$/,
+ // Special case for a simple path URL
+ simplePathPattern = /^(\/\/?(?!\/)[^\?\s]*)(\?[^\s]*)?$/,
+
// RFC 2396: characters reserved for delimiting URLs.
// We actually just auto-escape these.
delims = ['<', '>', '"', '`', ' ', '\r', '\n', '\t'],
// RFC 2396: characters not allowed for various reasons.
- unwise = ['{', '}', '|', '\\', '^', '~', '`'].concat(delims),
+ unwise = ['{', '}', '|', '\\', '^', '`'].concat(delims),
// Allowed by RFCs, but cause of XSS attacks. Always escape these.
- autoEscape = ['\''].concat(delims),
+ autoEscape = ['\''].concat(unwise),
// Characters that are never ever allowed in a hostname.
// Note that any invalid chars are also handled, but these
// are the ones that are *expected* to be seen, so we fast-path
// them.
- nonHostChars = ['%', '/', '?', ';', '#']
- .concat(unwise).concat(autoEscape),
+ nonHostChars = ['%', '/', '?', ';', '#'].concat(autoEscape),
hostEndingChars = ['/', '?', '#'],
hostnameMaxLen = 255,
hostnamePartPattern = /^[a-z0-9A-Z_-]{0,63}$/,
@@ -95,7 +98,7 @@ var protocolPattern = /^([a-z0-9.+-]+:)/i,
querystring = require('querystring');
function urlParse(url, parseQueryString, slashesDenoteHost) {
- if (url && typeof(url) === 'object' && url instanceof Url) return url;
+ if (url && util.isObject(url) && url instanceof Url) return url;
var u = new Url;
u.parse(url, parseQueryString, slashesDenoteHost);
@@ -103,7 +106,7 @@ function urlParse(url, parseQueryString, slashesDenoteHost) {
}
Url.prototype.parse = function(url, parseQueryString, slashesDenoteHost) {
- if (typeof url !== 'string') {
+ if (!util.isString(url)) {
throw new TypeError("Parameter 'url' must be a string, not " + typeof url);
}
@@ -119,6 +122,25 @@ Url.prototype.parse = function(url, parseQueryString, slashesDenoteHost) {
// This is to support parse stuff like " http://foo.com \n"
rest = rest.trim();
+ if (!slashesDenoteHost && hashSplit.length === 1) {
+ // Try fast path regexp
+ var simplePath = simplePathPattern.exec(rest);
+ if (simplePath) {
+ this.path = rest;
+ this.href = rest;
+ this.pathname = simplePath[1];
+ if (simplePath[2]) {
+ this.search = simplePath[2];
+ if (parseQueryString) {
+ this.query = querystring.parse(this.search.substr(1));
+ } else {
+ this.query = this.search.substr(1);
+ }
+ }
+ return this;
+ }
+ }
+
var proto = protocolPattern.exec(rest);
if (proto) {
proto = proto[0];
@@ -340,7 +362,7 @@ function urlFormat(obj) {
// If it's an obj, this is a no-op.
// this way, you can call url_format() on strings
// to clean up potentially wonky urls.
- if (typeof(obj) === 'string') obj = urlParse(obj);
+ if (util.isString(obj)) obj = urlParse(obj);
if (!(obj instanceof Url)) return Url.prototype.format.call(obj);
return obj.format();
}
@@ -370,7 +392,8 @@ Url.prototype.format = function() {
}
}
- if (this.query && typeof this.query === 'object' &&
+ if (this.query &&
+ util.isObject(this.query) &&
Object.keys(this.query).length) {
query = querystring.stringify(this.query);
}
@@ -414,16 +437,18 @@ function urlResolveObject(source, relative) {
}
Url.prototype.resolveObject = function(relative) {
- if (typeof relative === 'string') {
+ if (util.isString(relative)) {
var rel = new Url();
rel.parse(relative, false, true);
relative = rel;
}
var result = new Url();
- Object.keys(this).forEach(function(k) {
- result[k] = this[k];
- }, this);
+ var tkeys = Object.keys(this);
+ for (var tk = 0; tk < tkeys.length; tk++) {
+ var tkey = tkeys[tk];
+ result[tkey] = this[tkey];
+ }
// hash is always overridden, no matter what.
// even href="" will remove it.
@@ -438,10 +463,12 @@ Url.prototype.resolveObject = function(relative) {
// hrefs like //foo/bar always cut to the protocol.
if (relative.slashes && !relative.protocol) {
// take everything except the protocol from relative
- Object.keys(relative).forEach(function(k) {
- if (k !== 'protocol')
- result[k] = relative[k];
- });
+ var rkeys = Object.keys(relative);
+ for (var rk = 0; rk < rkeys.length; rk++) {
+ var rkey = rkeys[rk];
+ if (rkey !== 'protocol')
+ result[rkey] = relative[rkey];
+ }
//urlParse appends trailing / to urls like http://www.example.com
if (slashedProtocol[result.protocol] &&
@@ -463,9 +490,11 @@ Url.prototype.resolveObject = function(relative) {
// because that's known to be hostless.
// anything else is assumed to be absolute.
if (!slashedProtocol[relative.protocol]) {
- Object.keys(relative).forEach(function(k) {
+ var keys = Object.keys(relative);
+ for (var v = 0; v < keys.length; v++) {
+ var k = keys[v];
result[k] = relative[k];
- });
+ }
result.href = result.format();
return result;
}
@@ -554,7 +583,7 @@ Url.prototype.resolveObject = function(relative) {
srcPath = srcPath.concat(relPath);
result.search = relative.search;
result.query = relative.query;
- } else if (relative.search !== null && relative.search !== undefined) {
+ } else if (!util.isNullOrUndefined(relative.search)) {
// just pull out the search.
// like href='?foo'.
// Put this after the other two cases because it simplifies the booleans
@@ -573,7 +602,7 @@ Url.prototype.resolveObject = function(relative) {
result.search = relative.search;
result.query = relative.query;
//to support http.request
- if (result.pathname !== null || result.search !== null) {
+ if (!util.isNull(result.pathname) || !util.isNull(result.search)) {
result.path = (result.pathname ? result.pathname : '') +
(result.search ? result.search : '');
}
@@ -608,7 +637,7 @@ Url.prototype.resolveObject = function(relative) {
var up = 0;
for (var i = srcPath.length; i >= 0; i--) {
last = srcPath[i];
- if (last == '.') {
+ if (last === '.') {
srcPath.splice(i, 1);
} else if (last === '..') {
srcPath.splice(i, 1);
@@ -667,7 +696,7 @@ Url.prototype.resolveObject = function(relative) {
}
//to support request.http
- if (result.pathname !== null || result.search !== null) {
+ if (!util.isNull(result.pathname) || !util.isNull(result.search)) {
result.path = (result.pathname ? result.pathname : '') +
(result.search ? result.search : '');
}