diff --git a/lib/response.js b/lib/response.js index f965e539dd2..84b744f4772 100644 --- a/lib/response.js +++ b/lib/response.js @@ -277,14 +277,17 @@ res.jsonp = function jsonp(obj) { callback = callback[0]; } + // sanitize callback before entering JSONP branch + if (typeof callback === 'string' && callback.length !== 0) { + // restrict callback charset + callback = callback.replace(/[^\[\]\w$.]/g, ''); + } + // jsonp if (typeof callback === 'string' && callback.length !== 0) { this.set('X-Content-Type-Options', 'nosniff'); this.set('Content-Type', 'text/javascript'); - // restrict callback charset - callback = callback.replace(/[^\[\]\w$.]/g, ''); - if (body === undefined) { // empty argument body = '' diff --git a/test/res.jsonp.js b/test/res.jsonp.js index e043a3b07f2..d06fe5b1319 100644 --- a/test/res.jsonp.js +++ b/test/res.jsonp.js @@ -87,6 +87,47 @@ describe('res', function(){ .expect(200, /foobar\(\{\}\);/, done); }) + it('should fall back to JSON when callback sanitizes to empty', function(done){ + var app = express(); + + app.use(function(req, res){ + res.jsonp({ count: 1 }); + }); + + request(app) + .get('/?callback=!!!') + .expect('Content-Type', 'application/json; charset=utf-8') + .expect(200, '{"count":1}', done); + }) + + it('should fall back to JSON for callback with only special chars', function(done){ + var app = express(); + + app.get('/', function(req, res){ + res.type('application/vnd.example+json'); + res.jsonp({ hello: 'world' }); + }); + + request(app) + .get('/?callback=%3C%3E%21%40%23') + .expect('Content-Type', 'application/vnd.example+json; charset=utf-8') + .expect(utils.shouldNotHaveHeader('X-Content-Type-Options')) + .expect(200, '{"hello":"world"}', done); + }) + + it('should use sanitized callback with mixed valid/invalid chars', function(done){ + var app = express(); + + app.use(function(req, res){ + res.jsonp({ count: 1 }); + }); + + request(app) + .get('/?callback=foo!bar') + .expect('Content-Type', 'text/javascript; charset=utf-8') + .expect(200, /foobar\(\{"count":1\}\);/, done); + }) + it('should escape utf whitespace', function(done){ var app = express();