diff --git a/index.js b/index.js index 1a509318..f34a4748 100644 --- a/index.js +++ b/index.js @@ -169,6 +169,8 @@ function session(options) { if (cookieOptions.sameSite === 'auto') { req.session.cookie.sameSite = isSecure ? 'none' : 'lax'; } + + req.session.cookie._isModified = false; }; var storeImplementsTouch = typeof store.touch === 'function'; @@ -246,7 +248,7 @@ function session(options) { if (!touched) { // touch session - req.session.touch() + req.session.resetMaxAge(false) touched = true } @@ -342,7 +344,7 @@ function session(options) { if (!touched) { // touch session - req.session.touch() + req.session.resetMaxAge(false) touched = true } @@ -484,7 +486,7 @@ function session(options) { return cookieId !== req.sessionID ? saveUninitializedSession || isModified(req.session) - : rollingSessions || req.session.cookie.expires != null && isModified(req.session); + : rollingSessions || req.session.cookie.expires != null && (req.session.cookie._isModified || isModified(req.session)); } // generate a session if the browser doesn't send a sessionID diff --git a/session/cookie.js b/session/cookie.js index 8bb5907b..2f4842d3 100644 --- a/session/cookie.js +++ b/session/cookie.js @@ -26,6 +26,7 @@ var Cookie = module.exports = function Cookie(options) { this.path = '/'; this.maxAge = null; this.httpOnly = true; + this._isModified = false; if (options) { if (typeof options !== 'object') { @@ -42,6 +43,8 @@ var Cookie = module.exports = function Cookie(options) { if (this.originalMaxAge === undefined || this.originalMaxAge === null) { this.originalMaxAge = this.maxAge } + + this._isModified = false; }; /*! @@ -58,6 +61,7 @@ Cookie.prototype = { */ set expires(date) { + this._isModified = true; this._expires = date; this.originalMaxAge = this.maxAge; }, diff --git a/session/session.js b/session/session.js index fee7608c..72e2eb30 100644 --- a/session/session.js +++ b/session/session.js @@ -55,8 +55,15 @@ defineMethod(Session.prototype, 'touch', function touch() { * @api public */ -defineMethod(Session.prototype, 'resetMaxAge', function resetMaxAge() { +defineMethod(Session.prototype, 'resetMaxAge', function resetMaxAge(touched) { + var changed = this.cookie._isModified; + + if (touched !== false) { + changed = true; + } + this.cookie.maxAge = this.cookie.originalMaxAge; + this.cookie._isModified = changed; return this; }); diff --git a/session/store.js b/session/store.js index 3793877e..99a856fe 100644 --- a/session/store.js +++ b/session/store.js @@ -96,6 +96,7 @@ Store.prototype.createSession = function(req, sess){ // keep originalMaxAge intact sess.cookie.originalMaxAge = originalMaxAge + sess.cookie._isModified = false req.session = new Session(req, sess); return req.session; diff --git a/test/session.js b/test/session.js index 46fed763..1d47fca8 100644 --- a/test/session.js +++ b/test/session.js @@ -2015,6 +2015,36 @@ describe('session()', function(){ }) }) + it('should set cookie when only cookie is modified', function (done) { + var store = new session.MemoryStore() + var server = createServer({ store: store, resave: false }, function (req, res) { + if (!req.session.hit) { + req.session.hit = true + return res.end('created') + } + + req.session.cookie.maxAge = 300000 + req.session.touch() + req.session.save(function (err) { + if (err) return res.end(err.message) + res.end('saved') + }) + }) + + request(server) + .get('/') + .expect(shouldSetCookie('connect.sid')) + .expect(200, 'created', function (err, res) { + if (err) return done(err) + + request(server) + .get('/') + .set('Cookie', cookie(res)) + .expect(shouldSetCookie('connect.sid')) + .expect(200, 'saved', done) + }) + }) + it('should prevent end-of-request save on reloaded session', function (done) { var store = new session.MemoryStore() var server = createServer({ store: store }, function (req, res) {