diff --git a/History.md b/History.md index 2bf296d9..d28542bf 100644 --- a/History.md +++ b/History.md @@ -4,6 +4,8 @@ unreleased * add deprecation message to non-plural `req.accepts*` * add deprecation message to `res.send(body, status)` * add deprecation message to `res.vary()` + * add `headers` option to `res.sendfile` + - use to set headers on successful file transfer * add `mergeParams` option to `Router` - merges `req.params` from parent routes * deprecate things with `depd` module diff --git a/lib/response.js b/lib/response.js index 9a0a8864..13f215d3 100644 --- a/lib/response.js +++ b/lib/response.js @@ -278,9 +278,10 @@ res.jsonp = function(obj){ * * Options: * - * - `maxAge` defaulting to 0 - * - `root` root directory for relative filenames - * - `hidden` serve hidden files, defaulting to false + * - `maxAge` defaulting to 0 (can be string converted by `ms`) + * - `root` root directory for relative filenames + * - `headers` object of headers to serve with file + * - `hidden` serve hidden files, defaulting to false * * Other options are passed along to `send`. * @@ -331,14 +332,10 @@ res.sendfile = function(path, options, fn){ // clean up cleanup(); - if (!self.headersSent) self.removeHeader('Content-Disposition'); // callback available if (fn) return fn(err); - // list in limbo if there's no callback - if (self.headersSent) return; - // delegate next(err); } @@ -363,6 +360,21 @@ res.sendfile = function(path, options, fn){ file.on('error', error); file.on('directory', next); file.on('stream', stream); + + if (options.headers) { + // set headers on successful transfer + file.on('headers', function headers(res) { + var obj = options.headers; + var keys = Object.keys(obj); + + for (var i = 0; i < keys.length; i++) { + var k = keys[i]; + res.setHeader(k, obj[k]); + } + }); + } + + // pipe file.pipe(this); this.on('finish', cleanup); }; @@ -388,8 +400,13 @@ res.download = function(path, filename, fn){ } filename = filename || path; - this.set('Content-Disposition', contentDisposition(filename)); - return this.sendfile(path, fn); + + // set Content-Disposition when file is sent + var headers = { + 'Content-Disposition': contentDisposition(filename) + }; + + return this.sendfile(path, { headers: headers }, fn); }; /** diff --git a/test/res.sendfile.js b/test/res.sendfile.js index 6fcbf117..45e55845 100644 --- a/test/res.sendfile.js +++ b/test/res.sendfile.js @@ -130,6 +130,41 @@ describe('res', function(){ .expect(200, 'tobi', done); }) + it('should accept headers option', function(done){ + var app = express(); + var headers = { + 'x-success': 'sent', + 'x-other': 'done' + }; + + app.use(function(req, res){ + res.sendfile('test/fixtures/user.html', { headers: headers }); + }); + + request(app) + .get('/') + .expect('x-success', 'sent') + .expect('x-other', 'done') + .expect(200, done); + }) + + it('should ignore headers option on 404', function(done){ + var app = express(); + var headers = { 'x-success': 'sent' }; + + app.use(function(req, res){ + res.sendfile('test/fixtures/user.nothing', { headers: headers }); + }); + + request(app) + .get('/') + .expect(404, function (err, res) { + if (err) return done(err); + res.headers.should.not.have.property('x-success'); + done(); + }); + }) + describe('with an absolute path', function(){ it('should transfer the file', function(done){ var app = express();