diff options
Diffstat (limited to 'lib/url.js')
-rw-r--r-- | lib/url.js | 73 |
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 : ''); } |