diff --git a/README.md b/README.md index a1ed3fa1..b642a999 100644 --- a/README.md +++ b/README.md @@ -247,6 +247,24 @@ set to `false`, the cookie will not be set on a response with an uninitialized session. This option only modifies the behavior when an existing session was loaded for the request. +**Note** If this is set to true, option `rollingFunction` is ignored and every request will roll the session. + +##### rollingFunction + +Similar to [`rolling`](#rolling) option, but can conditionally roll the session. Only if the provided function returns true, the response will contain the cookie with the reset expiration to the original [`maxAge`](#cookiemaxage). + +```js +/** + * @param {Object} req - Request object from the middleware. + * @returns {Boolean} - Whether the session will be rolled or not. + * Use req.session to access the session object. + */ +... +rollingFunction: function([req]): Boolean {...} +``` + +**Note** In order for this function to be called, [`rolling`](#rolling) must be `false`. + ##### saveUninitialized Forces a session that is "uninitialized" to be saved to the store. A session is diff --git a/index.js b/index.js index 24221b48..37e57501 100644 --- a/index.js +++ b/index.js @@ -76,6 +76,7 @@ var defer = typeof setImmediate === 'function' * @param {Boolean} [options.proxy] * @param {Boolean} [options.resave] Resave unmodified sessions back to the store * @param {Boolean} [options.rolling] Enable/disable rolling session expiration + * @param {Function} [options.rollingFunction] Function for enabling/disabling rolling session expiration * @param {Boolean} [options.saveUninitialized] Save uninitialized sessions to the store * @param {String|Array} [options.secret] Secret for signing session ID * @param {Object} [options.store=MemoryStore] Session store @@ -108,6 +109,9 @@ function session(options) { // get the rolling session option var rollingSessions = Boolean(opts.rolling) + // get the rolling function option + var rollingFunction = opts.rollingFunction; + // get the save uninitialized session option var saveUninitializedSession = opts.saveUninitialized @@ -456,6 +460,14 @@ function session(options) { return false; } + if ( + !rollingSessions && + cookieId === req.sessionID && + typeof rollingFunction === "function" + ) { + return rollingFunction(req); + } + return cookieId !== req.sessionID ? saveUninitializedSession || isModified(req.session) : rollingSessions || req.session.cookie.expires != null && isModified(req.session); diff --git a/test/session.js b/test/session.js index 1e3b7124..12f85bbf 100644 --- a/test/session.js +++ b/test/session.js @@ -962,6 +962,112 @@ describe('session()', function(){ }); }); + it('should not force cookie if rolling function returns false', function(done){ + var server = createServer( + { + rollingFunction: function() { + return false; + } + }, + function(req, res) { + req.session.user = "bob"; + res.end(); + } + ); + + request(server) + .get('/') + .expect(shouldSetCookie('connect.sid')) + .expect(200, function(err, res){ + if (err) return done(err); + request(server) + .get('/') + .set('Cookie', cookie(res)) + .expect(shouldNotHaveHeader('Set-Cookie')) + .expect(200, done) + }); + }); + + it('should force cookie if rolling function returns false and rolling option is set', function(done){ + var server = createServer( + { + rollingFunction: function() { + return false; + }, + rolling: true + }, + function(req, res) { + req.session.user = "bob"; + res.end(); + } + ); + + request(server) + .get('/') + .expect(shouldSetCookie('connect.sid')) + .expect(200, function(err, res){ + if (err) return done(err); + request(server) + .get('/') + .set('Cookie', cookie(res)) + .expect(shouldSetCookie('connect.sid')) + .expect(200, done) + }); + }); + + it('should force cookie if rolling function returns true and rolling option is set', function(done){ + var server = createServer( + { + rollingFunction: function() { + return true; + }, + rolling: true + }, + function(req, res) { + req.session.user = "bob"; + res.end(); + } + ); + + request(server) + .get('/') + .expect(shouldSetCookie('connect.sid')) + .expect(200, function(err, res){ + if (err) return done(err); + request(server) + .get('/') + .set('Cookie', cookie(res)) + .expect(shouldSetCookie('connect.sid')) + .expect(200, done) + }); + }); + + it('should force cookie if rolling function returns true', function(done){ + var server = createServer( + { + rollingFunction: function() { + return true; + } + }, + function(req, res) { + req.session.user = "bob"; + res.end(); + } + ); + + request(server) + .get('/') + .expect(shouldSetCookie('connect.sid')) + .expect(200, function(err, res){ + if (err) return done(err); + request(server) + .get('/') + .set('Cookie', cookie(res)) + .expect(shouldSetCookie('connect.sid')) + .expect(200, done) + }); + }); + it('should not force cookie on uninitialized session if saveUninitialized option is set to false', function(done){ var store = new session.MemoryStore() var server = createServer({ store: store, rolling: true, saveUninitialized: false })