Skip to content

Commit 88e8a66

Browse files
committed
Improve session-ending error handling
closes #66
1 parent 3aa77da commit 88e8a66

File tree

3 files changed

+121
-6
lines changed

3 files changed

+121
-6
lines changed

History.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
unreleased
22
==========
33

4+
* Improve session-ending error handling
5+
- Errors are passed to `next(err)` instead of `console.error`
46
57
68
- Add `TRACE_DEPRECATION` environment variable

index.js

Lines changed: 19 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,15 @@ var warning = 'Warning: connect.session() MemoryStore is not\n'
5050
+ 'designed for a production environment, as it will leak\n'
5151
+ 'memory, and will not scale past a single process.';
5252

53+
/**
54+
* Node.js 0.8+ async implementation.
55+
*/
56+
57+
/* istanbul ignore next */
58+
var defer = typeof setImmediate === 'function'
59+
? setImmediate
60+
: function(fn){ process.nextTick(fn.bind.apply(fn, arguments)) }
61+
5362
/**
5463
* Setup session store with the given `options`.
5564
*
@@ -189,8 +198,11 @@ function session(options){
189198
if (shouldDestroy(req)) {
190199
// destroy session
191200
debug('destroying');
192-
store.destroy(req.sessionID, function(err){
193-
if (err) console.error(err.stack);
201+
store.destroy(req.sessionID, function ondestroy(err) {
202+
if (err) {
203+
defer(next, err);
204+
}
205+
194206
debug('destroyed');
195207

196208
if (sync) {
@@ -220,8 +232,11 @@ function session(options){
220232

221233
if (shouldSave(req)) {
222234
debug('saving');
223-
req.session.save(function(err){
224-
if (err) console.error(err.stack);
235+
req.session.save(function onsave(err) {
236+
if (err) {
237+
defer(next, err);
238+
}
239+
225240
debug('saved');
226241

227242
if (sync) {

test/session.js

Lines changed: 100 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -92,6 +92,54 @@ describe('session()', function(){
9292
})
9393
})
9494

95+
it('should pass session fetch error', function (done) {
96+
var store = new session.MemoryStore()
97+
var server = createServer({ store: store }, function (req, res) {
98+
res.end('hello, world')
99+
})
100+
101+
store.get = function destroy(sid, callback) {
102+
callback(new Error('boom!'))
103+
}
104+
105+
request(server)
106+
.get('/')
107+
.expect(200, 'hello, world', function (err, res) {
108+
if (err) return done(err)
109+
should(sid(res)).not.be.empty
110+
request(server)
111+
.get('/')
112+
.set('Cookie', cookie(res))
113+
.expect(500, 'boom!', done)
114+
})
115+
})
116+
117+
it('should treat ENOENT session fetch error as not found', function (done) {
118+
var count = 0
119+
var store = new session.MemoryStore()
120+
var server = createServer({ store: store }, function (req, res) {
121+
req.session.num = req.session.num || ++count
122+
res.end('session ' + req.session.num)
123+
})
124+
125+
store.get = function destroy(sid, callback) {
126+
var err = new Error('boom!')
127+
err.code = 'ENOENT'
128+
callback(err)
129+
}
130+
131+
request(server)
132+
.get('/')
133+
.expect(200, 'session 1', function (err, res) {
134+
if (err) return done(err)
135+
should(sid(res)).not.be.empty
136+
request(server)
137+
.get('/')
138+
.set('Cookie', cookie(res))
139+
.expect(200, 'session 2', done)
140+
})
141+
})
142+
95143
it('should create multiple sessions', function (done) {
96144
var cb = after(2, check)
97145
var count = 0
@@ -750,6 +798,27 @@ describe('session()', function(){
750798
.expect('set-cookie', /connect\.sid=/)
751799
.expect(200, done);
752800
});
801+
802+
it('should pass session save error', function (done) {
803+
var cb = after(2, done)
804+
var store = new session.MemoryStore()
805+
var server = createServer({ store: store, saveUninitialized: true }, function (req, res) {
806+
res.end('session saved')
807+
})
808+
809+
store.set = function destroy(sid, sess, callback) {
810+
callback(new Error('boom!'))
811+
}
812+
813+
server.on('error', function onerror(err) {
814+
err.message.should.equal('boom!')
815+
cb()
816+
})
817+
818+
request(server)
819+
.get('/')
820+
.expect(200, 'session saved', cb)
821+
})
753822
});
754823

755824
describe('unset option', function () {
@@ -844,6 +913,28 @@ describe('session()', function(){
844913
});
845914
});
846915
});
916+
917+
it('should pass session destroy error', function (done) {
918+
var cb = after(2, done)
919+
var store = new session.MemoryStore()
920+
var server = createServer({ store: store, unset: 'destroy' }, function (req, res) {
921+
req.session = null
922+
res.end('session destroyed')
923+
})
924+
925+
store.destroy = function destroy(sid, callback) {
926+
callback(new Error('boom!'))
927+
}
928+
929+
server.on('error', function onerror(err) {
930+
err.message.should.equal('boom!')
931+
cb()
932+
})
933+
934+
request(server)
935+
.get('/')
936+
.expect(200, 'session destroyed', cb)
937+
})
847938
});
848939

849940
describe('req.session', function(){
@@ -1506,17 +1597,24 @@ function createServer(opts, fn) {
15061597

15071598
var _session = session(options)
15081599

1509-
return http.createServer(function (req, res) {
1600+
var server = http.createServer(function (req, res) {
15101601
_session(req, res, function (err) {
1511-
if (err) {
1602+
if (err && !res._header) {
15121603
res.statusCode = err.status || 500
15131604
res.end(err.message)
15141605
return
15151606
}
15161607

1608+
if (err) {
1609+
server.emit('error', err)
1610+
return
1611+
}
1612+
15171613
respond(req, res)
15181614
})
15191615
})
1616+
1617+
return server
15201618
}
15211619

15221620
function end(req, res) {

0 commit comments

Comments
 (0)