diff --git a/README.md b/README.md index fe5076d8..0f996f57 100644 --- a/README.md +++ b/README.md @@ -182,6 +182,18 @@ app.use(session({ })) ``` +##### getDomainFromRequest + +Optional function to override the `Domain` `Set-Cookie` attribute. +Provide a function that returns a string that will be used as the +cookie domain. The function is given `req` as the first argument if +you want to use some value attached to `req` when generating the +domain (as for `genid`). This can be useful if the same app is +accessed from different families of domains, some of which should +share cookies. + +If this function is not provided, `cookie.domain` is used instead. + ##### name The name of the session ID cookie to set in the response (and read from in the diff --git a/index.js b/index.js index 9615346c..662db36d 100644 --- a/index.js +++ b/index.js @@ -114,10 +114,17 @@ function session(options) { // get the cookie signing secret var secret = opts.secret + // get a function for computing the domain from the request + var getDomainFromRequest = opts.getDomainFromRequest + if (typeof generateId !== 'function') { throw new TypeError('genid option must be a function'); } + if (getDomainFromRequest !== undefined && typeof getDomainFromRequest !== 'function') { + throw new TypeError('getDomainFromRequest option must be a function'); + } + if (resaveSession === undefined) { deprecate('undefined resave option; provide resave option'); resaveSession = true; @@ -160,6 +167,12 @@ function session(options) { req.session = new Session(req); req.session.cookie = new Cookie(cookieOptions); + if (getDomainFromRequest) { + // If a function was specified for computing the domain + // from the request, then use it now. + req.session.cookie.domain = getDomainFromRequest(req); + } + if (cookieOptions.secure === 'auto') { req.session.cookie.secure = issecure(req, trustProxy); } diff --git a/test/session.js b/test/session.js index f0b60fdf..3abce8f8 100644 --- a/test/session.js +++ b/test/session.js @@ -891,6 +891,37 @@ describe('session()', function(){ }); }); + describe('getDomainFromRequest option', function(){ + it('should reject non-function values', function(){ + assert.throws(session.bind(null, { getDomainFromRequest: 'bogus!' }), /getDomainFromRequest.*must/) + }); + + it('should work without getDomainFromRequest', function(done){ + request(createServer()) + .get('/') + .expect(shouldSetCookie('connect.sid')) + .expect(200, done) + }); + + it('should allow custom domain', function(done){ + function getDomainFromRequest(req) { return '.do.main' } + + request(createServer({ getDomainFromRequest: getDomainFromRequest })) + .get('/') + .expect(shouldSetCookieWithAttributeAndValue('connect.sid', 'Domain', '.do.main')) + .expect(200, done) + }); + + it('should provide req argument', function(done){ + function getDomainFromRequest(req) { return req.url } + + request(createServer({ getDomainFromRequest: getDomainFromRequest })) + .get('/foo') + .expect(shouldSetCookieWithAttributeAndValue('connect.sid', 'Domain', '/foo')) + .expect(200, done) + }); + }); + describe('key option', function(){ it('should default to "connect.sid"', function(done){ request(createServer())