aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--doc/api/url.markdown9
-rw-r--r--lib/url.js31
-rw-r--r--test/simple/test-url.js77
3 files changed, 104 insertions, 13 deletions
diff --git a/doc/api/url.markdown b/doc/api/url.markdown
index 6b8ff9d507..3ace699579 100644
--- a/doc/api/url.markdown
+++ b/doc/api/url.markdown
@@ -95,11 +95,12 @@ Take a parsed URL object, and return a formatted URL string.
* `hostname` will only be used if `host` is absent.
* `port` will only be used if `host` is absent.
* `host` will be used in place of `hostname` and `port`
-* `pathname` is treated the same with or without the leading `/` (slash)
-* `search` will be used in place of `query`
+* `pathname` is treated the same with or without the leading `/` (slash).
+* `path` is treated the same with `pathname` but able to contain `query` as well.
+* `search` will be used in place of `query`.
* `query` (object; see `querystring`) will only be used if `search` is absent.
-* `search` is treated the same with or without the leading `?` (question mark)
-* `hash` is treated the same with or without the leading `#` (pound sign, anchor)
+* `search` is treated the same with or without the leading `?` (question mark).
+* `hash` is treated the same with or without the leading `#` (pound sign, anchor).
## url.resolve(from, to)
diff --git a/lib/url.js b/lib/url.js
index 6a6a19d81e..56b1be9328 100644
--- a/lib/url.js
+++ b/lib/url.js
@@ -362,7 +362,7 @@ Url.prototype.parse = function(url, parseQueryString, slashesDenoteHost) {
}
// finally, reconstruct the href based on what has been validated.
- this.href = this.format();
+ this.href = this.format(parseQueryString);
return this;
};
@@ -377,7 +377,7 @@ function urlFormat(obj) {
return obj.format();
}
-Url.prototype.format = function() {
+Url.prototype.format = function(parseQueryString) {
var auth = this.auth || '';
if (auth) {
auth = encodeURIComponent(auth);
@@ -389,7 +389,26 @@ Url.prototype.format = function() {
pathname = this.pathname || '',
hash = this.hash || '',
host = false,
- query = '';
+ query = '',
+ search = '';
+
+ if (this.path) {
+ var qm = this.path.indexOf('?');
+ if (qm !== -1) {
+ query = this.path.slice(qm + 1);
+ search = '?' + query;
+ pathname = this.path.slice(0, qm);
+ } else {
+ if (parseQueryString) {
+ this.query = {};
+ this.search = '';
+ } else {
+ this.query = null;
+ this.search = null;
+ }
+ pathname = this.path;
+ }
+ }
if (this.host) {
host = auth + this.host;
@@ -402,13 +421,15 @@ Url.prototype.format = function() {
}
}
- if (this.query &&
+ if (!query &&
+ this.query &&
util.isObject(this.query) &&
Object.keys(this.query).length) {
query = querystring.stringify(this.query);
}
- var search = this.search || (query && ('?' + query)) || '';
+ if (!search)
+ search = this.search || (query && ('?' + query)) || '';
if (protocol && protocol.substr(-1) !== ':') protocol += ':';
diff --git a/test/simple/test-url.js b/test/simple/test-url.js
index 8bfedcdf3d..df72cc6f4e 100644
--- a/test/simple/test-url.js
+++ b/test/simple/test-url.js
@@ -1085,7 +1085,7 @@ var formatTests = {
// `#`,`?` in path
'/path/to/%%23%3F+=&.txt?foo=theA1#bar' : {
- href : '/path/to/%%23%3F+=&.txt?foo=theA1#bar',
+ href: '/path/to/%%23%3F+=&.txt?foo=theA1#bar',
pathname: '/path/to/%#?+=&.txt',
query: {
foo: 'theA1'
@@ -1095,7 +1095,7 @@ var formatTests = {
// `#`,`?` in path + `#` in query
'/path/to/%%23%3F+=&.txt?foo=the%231#bar' : {
- href : '/path/to/%%23%3F+=&.txt?foo=the%231#bar',
+ href: '/path/to/%%23%3F+=&.txt?foo=the%231#bar',
pathname: '/path/to/%#?+=&.txt',
query: {
foo: 'the#1'
@@ -1110,7 +1110,7 @@ var formatTests = {
hostname: 'ex.com',
hash: '#frag',
search: '?abc=the#1?&foo=bar',
- pathname: '/foo?100%m#r',
+ pathname: '/foo?100%m#r'
},
// `?` and `#` in search only
@@ -1120,8 +1120,77 @@ var formatTests = {
hostname: 'ex.com',
hash: '#frag',
search: '?abc=the#1?&foo=bar',
- pathname: '/fooA100%mBr',
+ pathname: '/fooA100%mBr'
+ },
+
+ // path
+ 'http://github.com/joyent/node#js1': {
+ href: 'http://github.com/joyent/node#js1',
+ protocol: 'http:',
+ hostname: 'github.com',
+ hash: '#js1',
+ path: '/joyent/node'
+ },
+
+ // pathname vs. path, path wins
+ 'http://github.com/joyent/node2#js1': {
+ href: 'http://github.com/joyent/node2#js1',
+ protocol: 'http:',
+ hostname: 'github.com',
+ hash: '#js1',
+ path: '/joyent/node2',
+ pathname: '/joyent/node'
+ },
+
+ // pathname with query/search
+ 'http://github.com/joyent/node?foo=bar#js2': {
+ href: 'http://github.com/joyent/node?foo=bar#js2',
+ protocol: 'http:',
+ hostname: 'github.com',
+ hash: '#js2',
+ path: '/joyent/node?foo=bar'
+ },
+
+ // path vs. query, path wins
+ 'http://github.com/joyent/node?foo=bar2#js3': {
+ href: 'http://github.com/joyent/node?foo=bar2#js3',
+ protocol: 'http:',
+ hostname: 'github.com',
+ hash: '#js3',
+ path: '/joyent/node?foo=bar2',
+ query: {foo: 'bar'}
+ },
+
+ // path vs. search, path wins
+ 'http://github.com/joyent/node?foo=bar3#js4': {
+ href: 'http://github.com/joyent/node?foo=bar3#js4',
+ protocol: 'http:',
+ hostname: 'github.com',
+ hash: '#js4',
+ path: '/joyent/node?foo=bar3',
+ search: '?foo=bar'
+ },
+
+ // path is present without ? vs. query given
+ 'http://github.com/joyent/node#js5': {
+ href: 'http://github.com/joyent/node#js5',
+ protocol: 'http:',
+ hostname: 'github.com',
+ hash: '#js5',
+ path: '/joyent/node',
+ query: {foo: 'bar'}
+ },
+
+ // path is present without ? vs. search given
+ 'http://github.com/joyent/node#js6': {
+ href: 'http://github.com/joyent/node#js6',
+ protocol: 'http:',
+ hostname: 'github.com',
+ hash: '#js6',
+ path: '/joyent/node',
+ search: '?foo=bar'
}
+
};
for (var u in formatTests) {
var expect = formatTests[u].href;