diff --git a/lib/response.js b/lib/response.js index f965e539dd2..a5e45741465 100644 --- a/lib/response.js +++ b/lib/response.js @@ -277,14 +277,16 @@ res.jsonp = function jsonp(obj) { callback = callback[0]; } + // restrict callback charset + if (typeof callback === 'string') { + 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..d68b476238d 100644 --- a/test/res.jsonp.js +++ b/test/res.jsonp.js @@ -87,6 +87,22 @@ describe('res', function(){ .expect(200, /foobar\(\{\}\);/, done); }) + it('should not use JSONP when callback sanitizes to empty', function(done){ + var app = express(); + + app.use(function(req, res){ + res.jsonp({ count: 1 }); + }); + + // A callback of all disallowed characters sanitizes to an empty string. + // This should fall back to plain JSON, not produce invalid JavaScript + // like: /**/ typeof === 'function' && ({"count":1}); + request(app) + .get('/?callback=!!!') + .expect('Content-Type', 'application/json; charset=utf-8') + .expect(200, '{"count":1}', done); + }) + it('should escape utf whitespace', function(done){ var app = express();