From ffef88e6862beb37250a50786665d182b5167b0e Mon Sep 17 00:00:00 2001 From: lqqyt2423 <974923609@qq.com> Date: Wed, 13 Apr 2022 22:10:05 +0800 Subject: [PATCH 1/3] Correctly invoke async router callback asynchronously --- lib/router/index.js | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/lib/router/index.js b/lib/router/index.js index 791a600f86a..afaaf6366f3 100644 --- a/lib/router/index.js +++ b/lib/router/index.js @@ -256,7 +256,8 @@ proto.handle = function handle(req, res, out) { // no match if (match !== true) { - return done(layerError); + setImmediate(done, layerError); + return; } // store route for dispatch on change From 6668a098055175a89218a5f7a7d39cb7e040cb81 Mon Sep 17 00:00:00 2001 From: lqqyt2423 <974923609@qq.com> Date: Wed, 13 Apr 2022 22:50:45 +0800 Subject: [PATCH 2/3] tests: add stack overflow test case --- test/Router.js | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/test/Router.js b/test/Router.js index 907b9726361..7a2c43a5d6f 100644 --- a/test/Router.js +++ b/test/Router.js @@ -76,6 +76,20 @@ describe('Router', function(){ router.handle({ url: '/', method: 'GET' }, { end: done }); }); + it('should not stack overflow with many registered sub routes', function(done){ + var handler = function(req, res, next){ next() }; + var router = new Router(); + + var subRouter; + for (var i = 0; i < 6000; i++) { + subRouter = new Router(); + subRouter.get('/thing' + i, handler) + router.use(subRouter); + } + + router.handle({ url: '/', method: 'GET' }, {}, done); + }); + describe('.handle', function(){ it('should dispatch', function(done){ var router = new Router(); From 538a78908417828de4ec1172a04e7c7bdc4d7cb5 Mon Sep 17 00:00:00 2001 From: lqqyt2423 <974923609@qq.com> Date: Thu, 14 Apr 2022 11:06:50 +0800 Subject: [PATCH 3/3] Fix handling very large stacks of sync middleware --- lib/router/index.js | 9 +++++++++ lib/router/route.js | 10 ++++++++++ test/Route.js | 11 +++++++++++ test/Router.js | 10 ++++++++++ 4 files changed, 40 insertions(+) diff --git a/lib/router/index.js b/lib/router/index.js index afaaf6366f3..794d6516981 100644 --- a/lib/router/index.js +++ b/lib/router/index.js @@ -142,6 +142,7 @@ proto.handle = function handle(req, res, out) { var protohost = getProtohost(req.url) || '' var removed = ''; var slashAdded = false; + var sync = 0; var paramcalled = {}; // store options for OPTIONS request @@ -203,6 +204,12 @@ proto.handle = function handle(req, res, out) { return; } + // max sync stack + if (++sync > 100) { + setImmediate(next, err); + return; + } + // get pathname of request var path = getPathname(req); @@ -322,6 +329,8 @@ proto.handle = function handle(req, res, out) { } else { layer.handle_request(req, res, next); } + + sync = 0; } }; diff --git a/lib/router/route.js b/lib/router/route.js index 178df0d5160..8a114a04d1d 100644 --- a/lib/router/route.js +++ b/lib/router/route.js @@ -98,6 +98,8 @@ Route.prototype._options = function _options() { Route.prototype.dispatch = function dispatch(req, res, done) { var idx = 0; var stack = this.stack; + var sync = 0; + if (stack.length === 0) { return done(); } @@ -127,6 +129,12 @@ Route.prototype.dispatch = function dispatch(req, res, done) { return done(err); } + // max sync stack + if (++sync > 100) { + setImmediate(next, err); + return; + } + if (layer.method && layer.method !== method) { return next(err); } @@ -136,6 +144,8 @@ Route.prototype.dispatch = function dispatch(req, res, done) { } else { layer.handle_request(req, res, next); } + + sync = 0; } }; diff --git a/test/Route.js b/test/Route.js index 8e7ddbdbcc1..c38d23005a5 100644 --- a/test/Route.js +++ b/test/Route.js @@ -70,6 +70,17 @@ describe('Route', function(){ done(); }); }) + + it('should not stack overflow with a large sync stack', function (done) { + var req = { method: 'GET', url: '/' }; + var route = new Route(''); + + for (var i = 0; i < 6000; i++) { + route.all(function (req, res, next) { next() }); + } + + route.dispatch(req, {}, done); + }) }) describe('.VERB', function(){ diff --git a/test/Router.js b/test/Router.js index 7a2c43a5d6f..68e816c2085 100644 --- a/test/Router.js +++ b/test/Router.js @@ -90,6 +90,16 @@ describe('Router', function(){ router.handle({ url: '/', method: 'GET' }, {}, done); }); + it('should not stack overflow with a large sync stack', function (done) { + var router = new Router(); + + for (var i = 0; i < 6000; i++) { + router.use(function (req, res, next) { next() }); + } + + router.handle({ url: '/', method: 'GET' }, {}, done); + }); + describe('.handle', function(){ it('should dispatch', function(done){ var router = new Router();