Skip to content

Commit 7e90c9e

Browse files
committed
Fix handling very large stacks of sync middleware
1 parent da11cc8 commit 7e90c9e

File tree

5 files changed

+58
-0
lines changed

5 files changed

+58
-0
lines changed

HISTORY.md

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

4+
* Fix handling very large stacks of sync middleware
45
* deps: safe-buffer@5.2.1
56

67
1.3.5 / 2020-03-24

index.js

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -163,6 +163,7 @@ Router.prototype.handle = function handle(req, res, callback) {
163163
var removed = ''
164164
var self = this
165165
var slashAdded = false
166+
var sync = 0
166167
var paramcalled = {}
167168

168169
// middleware and routes
@@ -218,6 +219,11 @@ Router.prototype.handle = function handle(req, res, callback) {
218219
return
219220
}
220221

222+
// max sync stack
223+
if (++sync > 100) {
224+
return defer(next, err)
225+
}
226+
221227
// get pathname of request
222228
var path = getPathname(req)
223229

@@ -340,6 +346,8 @@ Router.prototype.handle = function handle(req, res, callback) {
340346
} else {
341347
layer.handle_request(req, res, next)
342348
}
349+
350+
sync = 0
343351
}
344352
}
345353

lib/route.js

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,11 @@ var methods = require('methods')
2424

2525
var slice = Array.prototype.slice
2626

27+
/* istanbul ignore next */
28+
var defer = typeof setImmediate === 'function'
29+
? setImmediate
30+
: function (fn) { process.nextTick(fn.bind.apply(fn, arguments)) }
31+
2732
/**
2833
* Expose `Route`.
2934
*/
@@ -95,6 +100,8 @@ Route.prototype._methods = function _methods() {
95100
Route.prototype.dispatch = function dispatch(req, res, done) {
96101
var idx = 0
97102
var stack = this.stack
103+
var sync = 0
104+
98105
if (stack.length === 0) {
99106
return done()
100107
}
@@ -124,6 +131,11 @@ Route.prototype.dispatch = function dispatch(req, res, done) {
124131
return done(err)
125132
}
126133

134+
// max sync stack
135+
if (++sync > 100) {
136+
return defer(next, err)
137+
}
138+
127139
var layer
128140
var match
129141

@@ -143,6 +155,8 @@ Route.prototype.dispatch = function dispatch(req, res, done) {
143155
} else {
144156
layer.handle_request(req, res, next)
145157
}
158+
159+
sync = 0
146160
}
147161
}
148162

test/route.js

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -103,6 +103,24 @@ describe('Router', function () {
103103
.expect(404, done)
104104
})
105105

106+
it('should not stack overflow with a large sync stack', function (done) {
107+
this.timeout(5000) // long-running test
108+
109+
var router = new Router()
110+
var route = router.route('/foo')
111+
var server = createServer(router)
112+
113+
for (var i = 0; i < 6000; i++) {
114+
route.all(function (req, res, next) { next() })
115+
}
116+
117+
route.get(helloWorld)
118+
119+
request(server)
120+
.get('/foo')
121+
.expect(200, 'hello, world', done)
122+
})
123+
106124
describe('.all(...fn)', function () {
107125
it('should reject no arguments', function () {
108126
var router = new Router()

test/router.js

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -577,6 +577,23 @@ describe('Router', function () {
577577
.expect(404, done)
578578
})
579579

580+
it('should not stack overflow with a large sync stack', function (done) {
581+
this.timeout(5000) // long-running test
582+
583+
var router = new Router()
584+
var server = createServer(router)
585+
586+
for (var i = 0; i < 6000; i++) {
587+
router.use(function (req, res, next) { next() })
588+
}
589+
590+
router.use(helloWorld)
591+
592+
request(server)
593+
.get('/')
594+
.expect(200, 'hello, world', done)
595+
})
596+
580597
describe('error handling', function () {
581598
it('should invoke error function after next(err)', function (done) {
582599
var router = new Router()

0 commit comments

Comments
 (0)