Permalink
Browse files

implemented res.location

  • Loading branch information...
juliangruber committed Jan 13, 2013
1 parent 480d006 commit a4d7b75129330928b7144afa5da9a7fbcc2bd907
Showing with 230 additions and 187 deletions.
  1. +59 −29 lib/response.js
  2. +171 −0 test/res.location.js
  3. +0 −158 test/res.redirect.js
View
@@ -588,56 +588,41 @@ res.cookie = function(name, val, options){
return this;
};
+
/**
- * Redirect to the given `url` with optional response `status`
- * defaulting to 302.
+ * Set the location header to `url`.
*
* The given `url` can also be the name of a mapped url, for
* example by default express supports "back" which redirects
* to the _Referrer_ or _Referer_ headers or "/".
*
* Examples:
*
- * res.redirect('/foo/bar');
- * res.redirect('http://example.com');
- * res.redirect(301, 'http://example.com');
- * res.redirect('http://example.com', 301);
- * res.redirect('../login'); // /blog/post/1 -> /blog/login
+ * res.location('/foo/bar').;
+ * res.location('http://example.com');
+ * res.location('../login'); // /blog/post/1 -> /blog/login
*
* Mounting:
*
- * When an application is mounted, and `res.redirect()`
+ * When an application is mounted, and `res.location()`
* is given a path that does _not_ lead with "/". For
* example suppose a "blog" app is mounted at "/blog",
- * the following redirect would result in "/blog/login":
+ * the following call to `res.location()` would result
+ * in "/blog/login":
*
- * res.redirect('login');
+ * res.location('login');
*
- * While the leading slash would result in a redirect to "/login":
+ * While the leading slash would result in a location of "/login":
*
- * res.redirect('/login');
+ * res.location('/login');
*
* @param {String} url
- * @param {Number} code
* @api public
*/
-res.redirect = function(url){
+res.location = function(url){
var app = this.app
- , req = this.req
- , head = 'HEAD' == req.method
- , status = 302
- , body;
-
- // allow status / url
- if (2 == arguments.length) {
- if ('number' == typeof url) {
- status = url;
- url = arguments[1];
- } else {
- status = arguments[1];
- }
- }
+ , req = this.req;
// setup redirect map
var map = { back: req.get('Referrer') || '/' };
@@ -658,6 +643,52 @@ res.redirect = function(url){
}
}
+ // Respond
+ this.set('Location', url);
+ return this;
+};
+
+/**
+ * Redirect to the given `url` with optional response `status`
+ * defaulting to 302.
+ *
+ * The resulting `url` is determined by `res.location()`, so
+ * it will play nicely with mounted apps, relative paths,
+ * `"back"` etc.
+ *
+ * Examples:
+ *
+ * res.redirect('/foo/bar');
+ * res.redirect('http://example.com');
+ * res.redirect(301, 'http://example.com');
+ * res.redirect('http://example.com', 301);
+ * res.redirect('../login'); // /blog/post/1 -> /blog/login
+ *
+ * @param {String} url
+ * @param {Number} code
+ * @api public
+ */
+
+res.redirect = function(url){
+ var app = this.app
+ , head = 'HEAD' == this.req.method
+ , status = 302
+ , body;
+
+ // allow status / url
+ if (2 == arguments.length) {
+ if ('number' == typeof url) {
+ status = url;
+ url = arguments[1];
+ } else {
+ status = arguments[1];
+ }
+ }
+
+ // Set location header
+ this.location(url);
+ url = this.get('Location');
+
// Support text/{plain,html} by default
this.format({
text: function(){
@@ -676,7 +707,6 @@ res.redirect = function(url){
// Respond
this.statusCode = status;
- this.set('Location', url);
this.set('Content-Length', Buffer.byteLength(body));
this.end(head ? null : body);
};
View
@@ -0,0 +1,171 @@
+
+var express = require('../')
+ , request = require('./support/http');
+
+describe('res', function(){
+ describe('.location(url)', function(){
+ it('should set the header', function(done){
+ var app = express();
+
+ app.use(function(req, res){
+ res.location('http://google.com').end();
+ });
+
+ request(app)
+ .get('/')
+ .end(function(err, res){
+ res.headers.should.have.property('location', 'http://google.com');
+ done();
+ })
+ })
+
+ describe('with leading //', function(){
+ it('should pass through scheme-relative urls', function(done){
+ var app = express();
+
+ app.use(function(req, res){
+ res.location('//cuteoverload.com').end();
+ });
+
+ request(app)
+ .get('/')
+ .end(function(err, res){
+ res.headers.should.have.property('location', '//cuteoverload.com');
+ done();
+ })
+ })
+ })
+
+ describe('with leading /', function(){
+ it('should construct scheme-relative urls', function(done){
+ var app = express();
+
+ app.use(function(req, res){
+ res.location('/login').end();
+ });
+
+ request(app)
+ .get('/')
+ .end(function(err, res){
+ res.headers.should.have.property('location', '/login');
+ done();
+ })
+ })
+ })
+
+ describe('with leading ./', function(){
+ it('should construct path-relative urls', function(done){
+ var app = express();
+
+ app.use(function(req, res){
+ res.location('./edit').end();
+ });
+
+ request(app)
+ .get('/post/1')
+ .end(function(err, res){
+ res.headers.should.have.property('location', '/post/1/./edit');
+ done();
+ })
+ })
+ })
+
+ describe('with leading ../', function(){
+ it('should construct path-relative urls', function(done){
+ var app = express();
+
+ app.use(function(req, res){
+ res.location('../new').end();
+ });
+
+ request(app)
+ .get('/post/1')
+ .end(function(err, res){
+ res.headers.should.have.property('location', '/post/1/../new');
+ done();
+ })
+ })
+ })
+
+ describe('without leading /', function(){
+ it('should construct mount-point relative urls', function(done){
+ var app = express();
+
+ app.use(function(req, res){
+ res.location('login').end();
+ });
+
+ request(app)
+ .get('/')
+ .end(function(err, res){
+ res.headers.should.have.property('location', '/login');
+ done();
+ })
+ })
+ })
+
+ describe('when mounted', function(){
+ describe('deeply', function(){
+ it('should respect the mount-point', function(done){
+ var app = express()
+ , blog = express()
+ , admin = express();
+
+ admin.use(function(req, res){
+ res.location('login').end();
+ });
+
+ app.use('/blog', blog);
+ blog.use('/admin', admin);
+
+ request(app)
+ .get('/blog/admin')
+ .end(function(err, res){
+ res.headers.should.have.property('location', '/blog/admin/login');
+ done();
+ })
+ })
+ })
+
+ describe('omitting leading /', function(){
+ it('should respect the mount-point', function(done){
+ var app = express()
+ , admin = express();
+
+ admin.use(function(req, res){
+ res.location('admin/login').end();
+ });
+
+ app.use('/blog', admin);
+
+ request(app)
+ .get('/blog')
+ .end(function(err, res){
+ res.headers.should.have.property('location', '/blog/admin/login');
+ done();
+ })
+ })
+ })
+
+ describe('providing leading /', function(){
+ it('should ignore mount-point', function(done){
+ var app = express()
+ , admin = express();
+
+ admin.use(function(req, res){
+ res.location('/admin/login').end();
+ });
+
+ app.use('/blog', admin);
+
+ request(app)
+ .get('/blog')
+ .end(function(err, res){
+ res.headers.should.have.property('location', '/admin/login');
+ done();
+ })
+ })
+ })
+ })
+ })
+})
Oops, something went wrong.

0 comments on commit a4d7b75

Please sign in to comment.