diff --git a/History.md b/History.md index 95fda18cc..5aaf4fc41 100644 --- a/History.md +++ b/History.md @@ -1,4 +1,10 @@ +0.9.4 / 2012-09-20 +================== + + * fix `Buffer` responses [TooTallNate] + * fix `res.type` when a "type" param is present [TooTallNate] + 0.9.3 / 2012-09-18 ================== diff --git a/component.json b/component.json index 0c1ebd161..b66812db5 100644 --- a/component.json +++ b/component.json @@ -2,7 +2,7 @@ "name": "superagent", "repo": "visionmedia/superagent", "description": "awesome http requests", - "version": "0.9.3", + "version": "0.9.4", "keywords": ["http", "ajax", "request", "agent"], "main": "lib/superagent.js" } \ No newline at end of file diff --git a/lib/node/index.js b/lib/node/index.js index 493eff255..d90111b34 100644 --- a/lib/node/index.js +++ b/lib/node/index.js @@ -1,4 +1,3 @@ - /*! * superagent * Copyright (c) 2011 TJ Holowaychuk @@ -126,6 +125,9 @@ function Request(method, url) { this.writable = true; this._redirects = 0; this.redirects(5); + this._redirectData = false; + this._redirectAuth = false; + this._buffer = true; this.attachments = []; this.cookies = ''; this._redirectList = []; @@ -173,6 +175,33 @@ Request.prototype.redirects = function(n){ return this; }; +/** + * Set if redirects should forward data. + * + * @param {boolean} bool + * @return {Request} for chaining + * @api public + */ + +Request.prototype.redirectData = function(bool){ + this._redirectData = bool; + return this; +}; + +/** + * Set the if redirects should forward Auth, + * when redirected in the same domain. + * + * @param {boolean} bool + * @return {Request} for chaining + * @api public + */ + +Request.prototype.redirectAuth = function(bool){ + this._redirectAuth = bool; + return this; +}; + /** * Return a new `Part` for this request. * @@ -429,6 +458,10 @@ Request.prototype.clearTimeout = function(){ Request.prototype.redirect = function(res){ var url = res.headers.location; + var auth = this.req._headers.authorization; + var reqHost = this.req._headers.host; + var seeOther = 303 == res.statusCode; + var idempotent = 'HEAD' == this.method || 'GET' == this.method; if (!~url.indexOf('://')) { if (0 != url.indexOf('//')) { @@ -436,13 +469,23 @@ Request.prototype.redirect = function(res){ } url = this.protocol + url; } - - delete this.req; - this.method = 'HEAD' == this.method - ? this.method - : 'GET'; - this._data = null; this.url = url; + + delete this.req; + + if (this._redirectAuth && ~url.indexOf(reqHost)) { + this.set('Authorization', auth); + } + + if (!seeOther && !idempotent && this._redirectData) { + this.send(this._data); + } else { + this.method = 'HEAD' == this.method + ? this.method + : 'GET'; + this._data = null; + } + this._redirectList.push(url); this.emit('redirect', res); this.end(this._callback); @@ -653,12 +696,10 @@ Request.prototype.end = function(fn){ // buffered response if (buffer) { - res.text = ''; - res.setEncoding('utf8'); - res.on('data', function(chunk){ res.text += chunk; }); + var parse = 'text' == type + ? exports.parse.text + : exports.parse[utils.type(res.headers['content-type'] || '')]; - // parser - var parse = exports.parse[utils.type(res.headers['content-type'] || '')]; if (parse) { parse(res, function(err, obj){ // TODO: handle error diff --git a/lib/node/parsers/index.js b/lib/node/parsers/index.js index 0f69526b8..b47550e7e 100644 --- a/lib/node/parsers/index.js +++ b/lib/node/parsers/index.js @@ -1,3 +1,4 @@ exports['application/x-www-form-urlencoded'] = require('./urlencoded'); exports['application/json'] = require('./json'); +exports.text = require('./text'); diff --git a/lib/node/parsers/json.js b/lib/node/parsers/json.js index 8c100d932..ba244f269 100644 --- a/lib/node/parsers/json.js +++ b/lib/node/parsers/json.js @@ -1,11 +1,11 @@ module.exports = function(res, fn){ - var buf = ''; + res.text = ''; res.setEncoding('utf8'); - res.on('data', function(chunk){ buf += chunk; }); + res.on('data', function(chunk){ res.text += chunk; }); res.on('end', function(){ try { - fn(null, JSON.parse(buf)); + fn(null, JSON.parse(res.text)); } catch (err) { fn(err); } diff --git a/lib/node/parsers/text.js b/lib/node/parsers/text.js new file mode 100644 index 000000000..03575c698 --- /dev/null +++ b/lib/node/parsers/text.js @@ -0,0 +1,7 @@ + +module.exports = function(res, fn){ + res.text = ''; + res.setEncoding('utf8'); + res.on('data', function(chunk){ res.text += chunk; }); + res.on('end', fn); +}; \ No newline at end of file diff --git a/lib/node/parsers/urlencoded.js b/lib/node/parsers/urlencoded.js index 1859ed660..245c665f4 100644 --- a/lib/node/parsers/urlencoded.js +++ b/lib/node/parsers/urlencoded.js @@ -6,12 +6,12 @@ var qs = require('qs'); module.exports = function(res, fn){ - var buf = ''; + res.text = ''; res.setEncoding('ascii'); - res.on('data', function(chunk){ buf += chunk; }); + res.on('data', function(chunk){ res.text += chunk; }); res.on('end', function(){ try { - fn(null, qs.parse(buf)); + fn(null, qs.parse(res.text)); } catch (err) { fn(err); } diff --git a/lib/superagent.js b/lib/superagent.js index c951b5a0a..43a157277 100644 --- a/lib/superagent.js +++ b/lib/superagent.js @@ -46,18 +46,6 @@ ? function(s) { return s.trim(); } : function(s) { return s.replace(/(^\s*|\s*$)/g, ''); }; - /** - * Check if `obj` is a function. - * - * @param {Mixed} obj - * @return {Boolean} - * @api private - */ - - function isFunction(obj) { - return 'function' == typeof obj; - } - /** * Check if `obj` is an object. * @@ -67,7 +55,7 @@ */ function isObject(obj) { - return null != obj && 'object' == typeof obj; + return obj === Object(obj); } /** @@ -668,7 +656,7 @@ request.get = function(url, data, fn){ var req = request('GET', url); - if (isFunction(data)) fn = data, data = null; + if ('function' == typeof data) fn = data, data = null; if (data) req.query(data); if (fn) req.end(fn); return req; @@ -686,7 +674,7 @@ request.head = function(url, data, fn){ var req = request('HEAD', url); - if (isFunction(data)) fn = data, data = null; + if ('function' == typeof data) fn = data, data = null; if (data) req.send(data); if (fn) req.end(fn); return req; diff --git a/package.json b/package.json index a56736978..cc70a9427 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "superagent", - "version": "0.9.3", + "version": "0.9.4", "description": "elegant & feature rich browser / node HTTP with a fluent API", "keywords": [ "http", diff --git a/test/node/exports.js b/test/node/exports.js index d1871dc0a..46d487775 100644 --- a/test/node/exports.js +++ b/test/node/exports.js @@ -18,6 +18,6 @@ describe('exports', function(){ it('should expose .parse', function(){ Object.keys(request.parse) - .should.eql(['application/x-www-form-urlencoded', 'application/json']); + .should.eql(['application/x-www-form-urlencoded', 'application/json', 'text']); }) }) \ No newline at end of file diff --git a/test/node/redirects.js b/test/node/redirects.js index 0a0dd7739..225c338ab 100644 --- a/test/node/redirects.js +++ b/test/node/redirects.js @@ -5,7 +5,7 @@ var EventEmitter = require('events').EventEmitter , assert = require('assert') , app = express() , should = require('should'); - +app.use(express.bodyParser()); app.get('/', function(req, res){ res.redirect('/movies'); }); @@ -21,11 +21,25 @@ app.get('/movies/all', function(req, res){ app.get('/movies/all/0', function(req, res){ res.send('first movie page'); }); - app.post('/movie', function(req, res){ res.redirect('/movies/all/0'); }); - +app.post('/addmovie', function(req, res){ + res.redirect('/movies/add'); +}); +app.post('/movies/add', function(req, res){ + res.send('movie '+req.body.name+' added'); +}); +app.get('/private', function(req, res){ + res.redirect('/authed'); +}); +app.get('/authed', function(req, res){ + if (req.get('authorization')) { + res.send('authed'); + } else { + res.send('not authed'); + } +}); app.get('/tobi', function(req, res){ res.send('tobi'); }); @@ -118,5 +132,45 @@ describe('request', function(){ done(); }); }) + it('should redirect as POST if user specified', function(done){ + var redirects = []; + request + .post('http://localhost:3003/addmovie') + .send({ name: 'Methos' }) + .redirectData(true) + .redirects(2) + .on('redirect', function(res){ + redirects.push(res.headers.location); + }) + .end(function(res){ + var arr = []; + arr.push('//localhost:3003/movies/add'); + redirects.should.eql(arr); + res.text.should.equal('movie Methos added'); + done(); + }); + }) + }) + + describe('with Authorization', function(){ + it('should not redirect Authorization header',function(done){ + request + .get('http://localhost:3003/private') + .set('Authorization', 'Basic dXNlcm5hbWU6cGFzcw==') + .end(function(res){ + res.text.should.equal('not authed'); + done(); + }); + }) + it('should redirect Authorization header if specified',function(done){ + request + .get('http://localhost:3003/private') + .set('Authorization', 'Basic dXNlcm5hbWU6cGFzcw==') + .redirectAuth(true) + .end(function(res){ + res.text.should.equal('authed'); + done(); + }); + }) }) }) \ No newline at end of file