diff --git a/docs/index.md b/docs/index.md
index aa75acc98..da1b6020c 100644
--- a/docs/index.md
+++ b/docs/index.md
@@ -231,7 +231,7 @@ If you are calling Facebook's API, be sure to send an `Accept: application/json`
## Query strings
- `res.query(obj)` is a method which may be used to build up a query-string. For example populating `?format=json&dest=/login` on a __POST__:
+ `req.query(obj)` is a method which may be used to build up a query-string. For example populating `?format=json&dest=/login` on a __POST__:
request
.post('/')
@@ -605,7 +605,7 @@ Note that SuperAgent expects the global `Promise` object to be present. You'll n
SuperAgent has two implementations: one for web browsers (using XHR) and one for Node.JS (using core http module). By default Browserify and WebPack will pick the browser version.
-If want to use WebPack to compile code for Node.JS, you *must* specify [node target](webpack.github.io/docs/configuration.html#target) in its configuration.
+If want to use WebPack to compile code for Node.JS, you *must* specify [node target](https://webpack.github.io/docs/configuration.html#target) in its configuration.
### Using browser version in electron
diff --git a/index.html b/index.html
index f10fbd309..122726e0d 100644
--- a/index.html
+++ b/index.html
@@ -175,7 +175,7 @@
Retrying requests
Facebook and Accept JSON
If you are calling Facebook's API, be sure to send an Accept: application/json
header in your request. If you don't do this, Facebook will respond with Content-Type: text/javascript; charset=UTF-8
, which SuperAgent will not parse and thus res.body
will be undefined. You can do this with either req.accept('json')
or req.header('Accept', 'application/json')
. See issue 1078 for details.
Query strings
- res.query(obj)
is a method which may be used to build up a query-string. For example populating ?format=json&dest=/login
on a POST:
+ req.query(obj)
is a method which may be used to build up a query-string. For example populating ?format=json&dest=/login
on a POST:
request
.post('/')
.query({ format: 'json' })
@@ -447,7 +447,7 @@ CORS
Note that SuperAgent expects the global Promise
object to be present. You'll need a polyfill to use promises in Internet Explorer or Node.js 0.10.
Browser and node versions
SuperAgent has two implementations: one for web browsers (using XHR) and one for Node.JS (using core http module). By default Browserify and WebPack will pick the browser version.
-If want to use WebPack to compile code for Node.JS, you must specify node target in its configuration.
+If want to use WebPack to compile code for Node.JS, you must specify node target in its configuration.
Using browser version in electron
Electron developers report if you would prefer to use the browser version of SuperAgent instead of the Node version, you can require('superagent/superagent')
. Your requests will now show up in the Chrome developer tools Network tab. Note this environment is not covered by automated test suite and not officially supported.
diff --git a/lib/client.js b/lib/client.js
index 132542b75..38809ffba 100644
--- a/lib/client.js
+++ b/lib/client.js
@@ -15,7 +15,6 @@ if (typeof window !== 'undefined') { // Browser window
var Emitter = require('component-emitter');
var RequestBase = require('./request-base');
var isObject = require('./is-object');
-var isFunction = require('./is-function');
var ResponseBase = require('./response-base');
var shouldRetry = require('./should-retry');
@@ -643,32 +642,6 @@ Request.prototype.pipe = Request.prototype.write = function(){
throw Error("Streaming is not supported in browser version of superagent");
};
-/**
- * Compose querystring to append to req.url
- *
- * @api private
- */
-
-Request.prototype._appendQueryString = function(){
- var query = this._query.join('&');
- if (query) {
- this.url += (this.url.indexOf('?') >= 0 ? '&' : '?') + query;
- }
-
- if (this._sort) {
- var index = this.url.indexOf('?');
- if (index >= 0) {
- var queryArr = this.url.substring(index + 1).split('&');
- if (isFunction(this._sort)) {
- queryArr.sort(this._sort);
- } else {
- queryArr.sort();
- }
- this.url = this.url.substring(0, index) + '?' + queryArr.join('&');
- }
- }
-};
-
/**
* Check if `obj` is a host object,
* we don't want to serialize these :)
@@ -701,7 +674,7 @@ Request.prototype.end = function(fn){
this._callback = fn || noop;
// querystring
- this._appendQueryString();
+ this._finalizeQueryString();
return this._end();
};
diff --git a/lib/is-function.js b/lib/is-function.js
deleted file mode 100644
index 5fb118ef5..000000000
--- a/lib/is-function.js
+++ /dev/null
@@ -1,15 +0,0 @@
-/**
- * Check if `fn` is a function.
- *
- * @param {Function} fn
- * @return {Boolean}
- * @api private
- */
-var isObject = require('./is-object');
-
-function isFunction(fn) {
- var tag = isObject(fn) ? Object.prototype.toString.call(fn) : '';
- return tag === '[object Function]';
-}
-
-module.exports = isFunction;
diff --git a/lib/node/index.js b/lib/node/index.js
index ef06689af..a947631e0 100644
--- a/lib/node/index.js
+++ b/lib/node/index.js
@@ -24,7 +24,6 @@ var zlib = require('zlib');
var util = require('util');
var pkg = require('../../package.json');
var RequestBase = require('../request-base');
-var isFunction = require('../is-function');
var shouldRetry = require('../should-retry');
var request = exports = module.exports = function(method, url) {
@@ -144,7 +143,8 @@ function Request(method, url) {
this.redirects(method === 'HEAD' ? 0 : 5);
this.cookies = '';
this.qs = {};
- this.qsRaw = [];
+ this._query = [];
+ this.qsRaw = this._query; // Unused, for backwards compatibility only
this._redirectList = [];
this._streamRequest = false;
this.once('end', this.clearTimeout.bind(this));
@@ -306,11 +306,10 @@ Request.prototype.accept = function(type){
Request.prototype.query = function(val){
if ('string' == typeof val) {
- this.qsRaw.push(val);
- return this;
+ this._query.push(val);
+ } else {
+ extend(this.qs, val);
}
-
- extend(this.qs, val);
return this;
};
@@ -452,7 +451,7 @@ Request.prototype._redirect = function(res){
this._endCalled = false;
this.url = url;
this.qs = {};
- this.qsRaw = [];
+ this._query.length = 0;
this.set(headers);
this.emit('redirect', res);
this._redirectList.push(this.url);
@@ -485,12 +484,12 @@ Request.prototype.auth = function(user, pass, options){
}
switch (options.type) {
case 'bearer':
- return this.set('Authorization', 'Bearer ' + user);
-
+ return this.set('Authorization', 'Bearer ' + user);
+
default: // 'basic'
if (!~user.indexOf(':')) user = user + ':';
var str = new Buffer(user + pass).toString('base64');
- return this.set('Authorization', 'Basic ' + str);
+ return this.set('Authorization', 'Basic ' + str);
}
};
@@ -558,6 +557,18 @@ Request.prototype.request = function(){
var self = this;
var options = {};
+
+ try {
+ var query = qs.stringify(this.qs, { indices: false, strictNullHandling: true });
+ if (query) {
+ this.qs = {};
+ this._query.push(query);
+ }
+ this._finalizeQueryString();
+ } catch (e) {
+ return this.emit('error', e);
+ }
+
var url = this.url;
var retries = this._retries;
@@ -573,13 +584,13 @@ Request.prototype.request = function(){
// get the socket, path
var unixParts = url.path.match(/^([^/]+)(.+)$/);
options.socketPath = unixParts[1].replace(/%2F/g, '/');
- url.pathname = unixParts[2];
+ url.path = unixParts[2];
}
// options
options.method = this.method;
options.port = url.port;
- options.path = url.pathname;
+ options.path = url.path;
options.host = url.hostname;
options.ca = this._ca;
options.key = this._key;
@@ -621,10 +632,6 @@ Request.prototype.request = function(){
this.auth(auth[0], auth[1]);
}
- // query
- if (url.search)
- this.query(url.search.substr(1));
-
// add cookies
if (this.cookies) req.setHeader('Cookie', this.cookies);
@@ -633,12 +640,6 @@ Request.prototype.request = function(){
req.setHeader(key, this.header[key]);
}
- try {
- this._appendQueryString(req);
- } catch (e) {
- return this.emit('error', e);
- }
-
return req;
};
@@ -688,32 +689,6 @@ Request.prototype.callback = function(err, res){
fn(err, res);
};
-/**
- * Compose querystring to append to req.path
- *
- * @return {String} querystring
- * @api private
- */
-
-Request.prototype._appendQueryString = function(req){
- var query = qs.stringify(this.qs, { indices: false, strictNullHandling: true });
- query += ((query.length && this.qsRaw.length) ? '&' : '') + this.qsRaw.join('&');
- req.path += query.length ? (~req.path.indexOf('?') ? '&' : '?') + query : '';
-
- if (this._sort) {
- var index = req.path.indexOf('?');
- if (index >= 0) {
- var queryArr = req.path.substring(index + 1).split('&');
- if (isFunction(this._sort)) {
- queryArr.sort(this._sort);
- } else {
- queryArr.sort();
- }
- req.path = req.path.substring(0, index) + '?' + queryArr.join('&');
- }
- }
-};
-
/**
* Check if `obj` is a host object,
*
diff --git a/lib/request-base.js b/lib/request-base.js
index 0fc62a438..e1d2a87b8 100644
--- a/lib/request-base.js
+++ b/lib/request-base.js
@@ -554,6 +554,35 @@ RequestBase.prototype.sortQuery = function(sort) {
return this;
};
+/**
+ * Compose querystring to append to req.url
+ *
+ * @api private
+ */
+RequestBase.prototype._finalizeQueryString = function(){
+ var query = this._query.join('&');
+ if (query) {
+ this.url += (this.url.indexOf('?') >= 0 ? '&' : '?') + query;
+ }
+ this._query.length = 0; // Makes the call idempotent
+
+ if (this._sort) {
+ var index = this.url.indexOf('?');
+ if (index >= 0) {
+ var queryArr = this.url.substring(index + 1).split('&');
+ if ('function' === typeof this._sort) {
+ queryArr.sort(this._sort);
+ } else {
+ queryArr.sort();
+ }
+ this.url = this.url.substring(0, index) + '?' + queryArr.join('&');
+ }
+ }
+};
+
+// For backwards compat only
+RequestBase.prototype._appendQueryString = function() {console.trace("Unsupported");}
+
/**
* Invoke callback with timeout error.
*
diff --git a/package.json b/package.json
index c9bf8047b..1dbe7a917 100644
--- a/package.json
+++ b/package.json
@@ -1,6 +1,6 @@
{
"name": "superagent",
- "version": "3.5.2",
+ "version": "3.5.3-beta.2",
"description": "elegant & feature rich browser / node HTTP with a fluent API",
"scripts": {
"prepublish": "make all",
@@ -25,28 +25,28 @@
},
"dependencies": {
"component-emitter": "^1.2.0",
- "cookiejar": "^2.0.6",
- "debug": "^2.2.0",
+ "cookiejar": "^2.1.0",
+ "debug": "^2.6.0",
"extend": "^3.0.0",
"form-data": "^2.1.1",
"formidable": "^1.1.1",
"methods": "^1.1.1",
"mime": "^1.3.4",
- "qs": "^6.1.0",
+ "qs": "^6.4.0",
"readable-stream": "^2.0.5"
},
"devDependencies": {
- "Base64": "^1.0.0",
+ "Base64": "^1.0.1",
"basic-auth-connect": "^1.0.0",
- "body-parser": "^1.15.0",
- "browserify": "^14.0.0",
- "cookie-parser": "^1.4.1",
- "express": "^4.13.4",
- "express-session": "^1.13.0",
- "marked": "^0.3.5",
+ "body-parser": "^1.17.0",
+ "browserify": "^14.1.0",
+ "cookie-parser": "^1.4.3",
+ "express": "^4.15.2",
+ "express-session": "^1.15.0",
+ "marked": "^0.3.6",
"mocha": "^3.1.2",
- "multer": "^1.2.0",
- "should": "^11.1.1",
+ "multer": "^1.3.0",
+ "should": "^11.2.0",
"should-http": "^0.1.1",
"zuul": "^3.11.1"
},
diff --git a/test.html b/test.html
index e40fc8bbe..6c5cb09b3 100644
--- a/test.html
+++ b/test.html
@@ -1806,15 +1806,18 @@ .retry(count)
}
});
should handle successful request after repeat attempt from server timeout
- request
-.get(base + '/delay/400/ok/' + uniqid())
+ var url = '/delay/400/ok/' + uniqid() + '?built=in';
+request
+.get(base + url)
+.query("string=ified")
+.query({"json":"ed"})
.timeout(200)
.retry(2)
.end(function(err, res){
try {
assert.ifError(err);
assert(res.ok, 'response should be ok');
- assert(res.text, 'res.text');
+ assert.equal(res.text, 'ok = ' + url + '&string=ified&json=ed');
done();
} catch(err) {
done(err);
diff --git a/test/retry.js b/test/retry.js
index 8d3d429b1..ee9223e4a 100644
--- a/test/retry.js
+++ b/test/retry.js
@@ -142,15 +142,18 @@ describe('.retry(count)', function(){
});
it('should handle successful request after repeat attempt from server timeout', function(done) {
+ var url = '/delay/400/ok/' + uniqid() + '?built=in';
request
- .get(base + '/delay/400/ok/' + uniqid())
+ .get(base + url)
+ .query("string=ified")
+ .query({"json":"ed"})
.timeout(200)
.retry(2)
.end(function(err, res){
try {
assert.ifError(err);
assert(res.ok, 'response should be ok');
- assert(res.text, 'res.text');
+ assert.equal(res.text, 'ok = ' + url + '&string=ified&json=ed');
done();
} catch(err) {
done(err);
diff --git a/test/support/server.js b/test/support/server.js
index fe37f4518..5c49cf4f3 100644
--- a/test/support/server.js
+++ b/test/support/server.js
@@ -448,7 +448,7 @@ app.get('/delay/:ms/ok/:id', function(req, res){
res.sendStatus(200);
}, ms);
} else {
- res.send('ok');
+ res.send('ok = ' + req.url);
delete called[id];
}
});