From a2dfc56a4982e0a33c67d6d0c22e087e95bff79e Mon Sep 17 00:00:00 2001 From: Douglas Christopher Wilson Date: Fri, 20 May 2022 09:33:19 -0400 Subject: [PATCH 01/77] build: mocha@10.0.0 --- .github/workflows/ci.yml | 2 ++ appveyor.yml | 3 +++ package.json | 2 +- 3 files changed, 6 insertions(+), 1 deletion(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index a4b40dc982..6df74b37f8 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -87,9 +87,11 @@ jobs: - name: Node.js 12.x node-version: "12.22" + npm-i: mocha@9.2.2 - name: Node.js 13.x node-version: "13.14" + npm-i: mocha@9.2.2 - name: Node.js 14.x node-version: "14.19" diff --git a/appveyor.yml b/appveyor.yml index 80802e180e..e9b28e7d0f 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -47,6 +47,7 @@ install: # - use 6.x for Node.js < 8 # - use 7.x for Node.js < 10 # - use 8.x for Node.js < 12 + # - use 9.x for Node.js < 14 if ([int]$env:nodejs_version.split(".")[0] -lt 4) { npm install --silent --save-dev mocha@3.5.3 } elseif ([int]$env:nodejs_version.split(".")[0] -lt 6) { @@ -57,6 +58,8 @@ install: npm install --silent --save-dev mocha@7.2.0 } elseif ([int]$env:nodejs_version.split(".")[0] -lt 12) { npm install --silent --save-dev mocha@8.4.0 + } elseif ([int]$env:nodejs_version.split(".")[0] -lt 14) { + npm install --silent --save-dev mocha@9.2.2 } - ps: | # nyc for test coverage diff --git a/package.json b/package.json index f5872a5333..6880db2524 100644 --- a/package.json +++ b/package.json @@ -71,7 +71,7 @@ "hbs": "4.2.0", "marked": "0.7.0", "method-override": "3.0.0", - "mocha": "9.2.2", + "mocha": "10.0.0", "morgan": "1.10.0", "multiparty": "4.2.3", "nyc": "15.1.0", From 745a63f8256828a061e1b2f0a5f8e52eb9538da1 Mon Sep 17 00:00:00 2001 From: Douglas Christopher Wilson Date: Fri, 20 May 2022 09:34:47 -0400 Subject: [PATCH 02/77] build: ejs@3.1.8 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 6880db2524..3430f77097 100644 --- a/package.json +++ b/package.json @@ -65,7 +65,7 @@ "connect-redis": "3.4.2", "cookie-parser": "1.4.6", "cookie-session": "2.0.0", - "ejs": "3.1.7", + "ejs": "3.1.8", "eslint": "7.32.0", "express-session": "1.17.2", "hbs": "4.2.0", From ab2c70b954ac2ceb3aaf466b0f59089999952dd0 Mon Sep 17 00:00:00 2001 From: Douglas Christopher Wilson Date: Fri, 20 May 2022 09:35:20 -0400 Subject: [PATCH 03/77] build: Node.js@18.1 --- .github/workflows/ci.yml | 2 +- appveyor.yml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 6df74b37f8..b7ad457829 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -106,7 +106,7 @@ jobs: node-version: "17.9" - name: Node.js 18.x - node-version: "18.0" + node-version: "18.1" steps: - uses: actions/checkout@v2 diff --git a/appveyor.yml b/appveyor.yml index e9b28e7d0f..b78a0b1550 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -19,7 +19,7 @@ environment: - nodejs_version: "15.14" - nodejs_version: "16.15" - nodejs_version: "17.9" - - nodejs_version: "18.0" + - nodejs_version: "18.1" cache: - node_modules install: From 7ec5dd2b3c5e7379f68086dae72859f5573c8b9b Mon Sep 17 00:00:00 2001 From: Douglas Christopher Wilson Date: Fri, 20 May 2022 09:37:20 -0400 Subject: [PATCH 04/77] Fix regression routing a large stack in a single route fixes #4913 --- History.md | 5 +++++ lib/router/route.js | 16 ++++++++-------- test/Route.js | 11 ++++++++++- 3 files changed, 23 insertions(+), 9 deletions(-) diff --git a/History.md b/History.md index 4c12ec9735..cbf4b5249f 100644 --- a/History.md +++ b/History.md @@ -1,3 +1,8 @@ +unreleased +========== + + * Fix regression routing a large stack in a single route + 4.18.1 / 2022-04-29 =================== diff --git a/lib/router/route.js b/lib/router/route.js index 5adaa125e2..cc643ac8bd 100644 --- a/lib/router/route.js +++ b/lib/router/route.js @@ -124,21 +124,21 @@ Route.prototype.dispatch = function dispatch(req, res, done) { return done(err) } - var layer = stack[idx++]; - if (!layer) { - return done(err); - } - // max sync stack if (++sync > 100) { return setImmediate(next, err) } - if (layer.method && layer.method !== method) { - return next(err); + var layer = stack[idx++] + + // end of layers + if (!layer) { + return done(err) } - if (err) { + if (layer.method && layer.method !== method) { + next(err) + } else if (err) { layer.handle_error(err, req, res, next); } else { layer.handle_request(req, res, next); diff --git a/test/Route.js b/test/Route.js index 3bdc8d7df2..64dbad60ce 100644 --- a/test/Route.js +++ b/test/Route.js @@ -19,8 +19,16 @@ describe('Route', function(){ var req = { method: 'GET', url: '/' } var route = new Route('/foo') + route.get(function (req, res, next) { + req.counter = 0 + next() + }) + for (var i = 0; i < 6000; i++) { - route.all(function (req, res, next) { next() }) + route.all(function (req, res, next) { + req.counter++ + next() + }) } route.get(function (req, res, next) { @@ -31,6 +39,7 @@ describe('Route', function(){ route.dispatch(req, {}, function (err) { if (err) return done(err) assert.ok(req.called) + assert.strictEqual(req.counter, 6000) done() }) }) From 97f0a518d8d697e310abf293a71383cf9d04d749 Mon Sep 17 00:00:00 2001 From: Douglas Christopher Wilson Date: Fri, 20 May 2022 11:54:35 -0400 Subject: [PATCH 05/77] tests: verify all handlers called in stack tests --- test/Router.js | 22 ++++++++++++++++++++-- 1 file changed, 20 insertions(+), 2 deletions(-) diff --git a/test/Router.js b/test/Router.js index fcfee80625..0d0502ab40 100644 --- a/test/Router.js +++ b/test/Router.js @@ -83,11 +83,20 @@ describe('Router', function(){ var router = new Router() + router.get('/foo', function (req, res, next) { + req.counter = 0 + next() + }) + for (var i = 0; i < 6000; i++) { - router.get('/foo', function (req, res, next) { next() }) + router.get('/foo', function (req, res, next) { + req.counter++ + next() + }) } router.get('/foo', function (req, res) { + assert.strictEqual(req.counter, 6000) res.end() }) @@ -99,11 +108,20 @@ describe('Router', function(){ var router = new Router() + router.use(function (req, res, next) { + req.counter = 0 + next() + }) + for (var i = 0; i < 6000; i++) { - router.use(function (req, res, next) { next() }) + router.use(function (req, res, next) { + req.counter++ + next() + }) } router.use(function (req, res) { + assert.strictEqual(req.counter, 6000) res.end() }) From 2c47827053233e707536019a15499ccf5496dc9d Mon Sep 17 00:00:00 2001 From: Alexandru Dragomir Date: Fri, 20 May 2022 18:49:44 +0300 Subject: [PATCH 06/77] examples: remove unused function arguments in params closes #4914 --- examples/params/index.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/examples/params/index.js b/examples/params/index.js index b6fc483c8b..f3cd8457eb 100644 --- a/examples/params/index.js +++ b/examples/params/index.js @@ -51,7 +51,7 @@ app.get('/', function(req, res){ * GET :user. */ -app.get('/user/:user', function(req, res, next){ +app.get('/user/:user', function (req, res) { res.send('user ' + req.user.name); }); @@ -59,7 +59,7 @@ app.get('/user/:user', function(req, res, next){ * GET users :from - :to. */ -app.get('/users/:from-:to', function(req, res, next){ +app.get('/users/:from-:to', function (req, res) { var from = req.params.from; var to = req.params.to; var names = users.map(function(user){ return user.name; }); From 8d98e86d7fe4e4dd50e42e73301b0bb7b7132758 Mon Sep 17 00:00:00 2001 From: Douglas Christopher Wilson Date: Thu, 18 Aug 2022 23:00:36 -0400 Subject: [PATCH 07/77] build: Node.js@16.17 --- .github/workflows/ci.yml | 2 +- appveyor.yml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index b7ad457829..5be813b2fe 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -100,7 +100,7 @@ jobs: node-version: "15.14" - name: Node.js 16.x - node-version: "16.15" + node-version: "16.17" - name: Node.js 17.x node-version: "17.9" diff --git a/appveyor.yml b/appveyor.yml index b78a0b1550..ef183ed7d7 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -17,7 +17,7 @@ environment: - nodejs_version: "13.14" - nodejs_version: "14.19" - nodejs_version: "15.14" - - nodejs_version: "16.15" + - nodejs_version: "16.17" - nodejs_version: "17.9" - nodejs_version: "18.1" cache: From 97131bcda8bd3cdbe53ef14fbd08dcc23a53e758 Mon Sep 17 00:00:00 2001 From: Douglas Christopher Wilson Date: Thu, 18 Aug 2022 23:01:25 -0400 Subject: [PATCH 08/77] build: Node.js@18.7 --- .github/workflows/ci.yml | 2 +- appveyor.yml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 5be813b2fe..1ad8d11766 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -106,7 +106,7 @@ jobs: node-version: "17.9" - name: Node.js 18.x - node-version: "18.1" + node-version: "18.7" steps: - uses: actions/checkout@v2 diff --git a/appveyor.yml b/appveyor.yml index ef183ed7d7..071f0de092 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -19,7 +19,7 @@ environment: - nodejs_version: "15.14" - nodejs_version: "16.17" - nodejs_version: "17.9" - - nodejs_version: "18.1" + - nodejs_version: "18.7" cache: - node_modules install: From ecd7572f1e920b7a512452b8d9806ae617a99c54 Mon Sep 17 00:00:00 2001 From: Douglas Christopher Wilson Date: Thu, 18 Aug 2022 23:41:10 -0400 Subject: [PATCH 09/77] build: Node.js@14.20 --- .github/workflows/ci.yml | 2 +- appveyor.yml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 1ad8d11766..5d2cef5a4d 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -94,7 +94,7 @@ jobs: npm-i: mocha@9.2.2 - name: Node.js 14.x - node-version: "14.19" + node-version: "14.20" - name: Node.js 15.x node-version: "15.14" diff --git a/appveyor.yml b/appveyor.yml index 071f0de092..7bf0141b38 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -15,7 +15,7 @@ environment: - nodejs_version: "11.15" - nodejs_version: "12.22" - nodejs_version: "13.14" - - nodejs_version: "14.19" + - nodejs_version: "14.20" - nodejs_version: "15.14" - nodejs_version: "16.17" - nodejs_version: "17.9" From 644f6464b9f61cbafa8f880636b1aa5237d95bad Mon Sep 17 00:00:00 2001 From: Douglas Christopher Wilson Date: Thu, 18 Aug 2022 23:42:39 -0400 Subject: [PATCH 10/77] build: supertest@6.2.4 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 3430f77097..cbfa910ff0 100644 --- a/package.json +++ b/package.json @@ -76,7 +76,7 @@ "multiparty": "4.2.3", "nyc": "15.1.0", "pbkdf2-password": "1.2.1", - "supertest": "6.2.3", + "supertest": "6.2.4", "vhost": "~3.0.2" }, "engines": { From 33e8dc303af9277f8a7e4f46abfdcb5e72f6797b Mon Sep 17 00:00:00 2001 From: REALSTEVEIG <101066723+REALSTEVEIG@users.noreply.github.com> Date: Sat, 11 Jun 2022 21:26:10 +0100 Subject: [PATCH 11/77] docs: use Node.js name style closes #4926 --- Readme.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Readme.md b/Readme.md index 720bf38922..9b8bc34a0c 100644 --- a/Readme.md +++ b/Readme.md @@ -1,6 +1,6 @@ [![Express Logo](https://i.cloudup.com/zfY6lL7eFa-3000x3000.png)](http://expressjs.com/) - Fast, unopinionated, minimalist web framework for [node](http://nodejs.org). + Fast, unopinionated, minimalist web framework for [Node.js](http://nodejs.org). [![NPM Version][npm-version-image]][npm-url] [![NPM Install Size][npm-install-size-image]][npm-install-size-url] From 340be0f79afb9b3176afb76235aa7f92acbd5050 Mon Sep 17 00:00:00 2001 From: Douglas Christopher Wilson Date: Wed, 5 Oct 2022 22:40:51 -0400 Subject: [PATCH 12/77] build: eslint@8.24.0 --- .github/workflows/ci.yml | 4 ++-- package.json | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 5d2cef5a4d..6125da491a 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -133,8 +133,8 @@ jobs: shell: bash run: | # eslint for linting - # - remove on Node.js < 10 - if [[ "$(cut -d. -f1 <<< "${{ matrix.node-version }}")" -lt 10 ]]; then + # - remove on Node.js < 12 + if [[ "$(cut -d. -f1 <<< "${{ matrix.node-version }}")" -lt 12 ]]; then node -pe 'Object.keys(require("./package").devDependencies).join("\n")' | \ grep -E '^eslint(-|$)' | \ sort -r | \ diff --git a/package.json b/package.json index cbfa910ff0..defab0eec0 100644 --- a/package.json +++ b/package.json @@ -66,7 +66,7 @@ "cookie-parser": "1.4.6", "cookie-session": "2.0.0", "ejs": "3.1.8", - "eslint": "7.32.0", + "eslint": "8.24.0", "express-session": "1.17.2", "hbs": "4.2.0", "marked": "0.7.0", From 689d175b8b39d8860b81d723233fb83d15201827 Mon Sep 17 00:00:00 2001 From: Douglas Christopher Wilson Date: Thu, 6 Oct 2022 10:26:18 -0400 Subject: [PATCH 13/77] deps: body-parser@1.20.1 --- History.md | 3 +++ package.json | 2 +- 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/History.md b/History.md index cbf4b5249f..389c837b08 100644 --- a/History.md +++ b/History.md @@ -2,6 +2,9 @@ unreleased ========== * Fix regression routing a large stack in a single route + * deps: body-parser@1.20.1 + - deps: qs@6.11.0 + - perf: remove unnecessary object clone 4.18.1 / 2022-04-29 =================== diff --git a/package.json b/package.json index defab0eec0..2c2d40a73f 100644 --- a/package.json +++ b/package.json @@ -30,7 +30,7 @@ "dependencies": { "accepts": "~1.3.8", "array-flatten": "1.1.1", - "body-parser": "1.20.0", + "body-parser": "1.20.1", "content-disposition": "0.5.4", "content-type": "~1.0.4", "cookie": "0.5.0", From 24b3dc551670ac4fb0cd5a2bd5ef643c9525e60f Mon Sep 17 00:00:00 2001 From: Douglas Christopher Wilson Date: Thu, 6 Oct 2022 10:27:01 -0400 Subject: [PATCH 14/77] deps: qs@6.11.0 --- History.md | 1 + package.json | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/History.md b/History.md index 389c837b08..a05baee617 100644 --- a/History.md +++ b/History.md @@ -5,6 +5,7 @@ unreleased * deps: body-parser@1.20.1 - deps: qs@6.11.0 - perf: remove unnecessary object clone + * deps: qs@6.11.0 4.18.1 / 2022-04-29 =================== diff --git a/package.json b/package.json index 2c2d40a73f..a7815d9fbe 100644 --- a/package.json +++ b/package.json @@ -49,7 +49,7 @@ "parseurl": "~1.3.3", "path-to-regexp": "0.1.7", "proxy-addr": "~2.0.7", - "qs": "6.10.3", + "qs": "6.11.0", "range-parser": "~1.2.1", "safe-buffer": "5.2.1", "send": "0.18.0", From f56ce73186e885a938bfdb3d3d1005a58e6ae12b Mon Sep 17 00:00:00 2001 From: Douglas Christopher Wilson Date: Thu, 6 Oct 2022 10:28:13 -0400 Subject: [PATCH 15/77] build: supertest@6.3.0 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index a7815d9fbe..6a11013c72 100644 --- a/package.json +++ b/package.json @@ -76,7 +76,7 @@ "multiparty": "4.2.3", "nyc": "15.1.0", "pbkdf2-password": "1.2.1", - "supertest": "6.2.4", + "supertest": "6.3.0", "vhost": "~3.0.2" }, "engines": { From bb7907b932afe3a19236a642f6054b6c8f7349a0 Mon Sep 17 00:00:00 2001 From: Douglas Christopher Wilson Date: Fri, 7 Oct 2022 17:48:59 -0400 Subject: [PATCH 16/77] build: Node.js@18.10 closes #5014 --- .github/workflows/ci.yml | 2 +- appveyor.yml | 2 +- test/res.sendFile.js | 7 ++++--- 3 files changed, 6 insertions(+), 5 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 6125da491a..cd93ab223d 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -106,7 +106,7 @@ jobs: node-version: "17.9" - name: Node.js 18.x - node-version: "18.7" + node-version: "18.10" steps: - uses: actions/checkout@v2 diff --git a/appveyor.yml b/appveyor.yml index 7bf0141b38..1fca21801e 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -19,7 +19,7 @@ environment: - nodejs_version: "15.14" - nodejs_version: "16.17" - nodejs_version: "17.9" - - nodejs_version: "18.7" + - nodejs_version: "18.10" cache: - node_modules install: diff --git a/test/res.sendFile.js b/test/res.sendFile.js index eb71adeb6a..4db0a3b6a4 100644 --- a/test/res.sendFile.js +++ b/test/res.sendFile.js @@ -1050,12 +1050,13 @@ describe('res', function(){ app.use(function(req, res){ res.sendfile('test/fixtures/user.html', function(err){ - assert(!res.headersSent); - assert.strictEqual(req.socket.listeners('error').length, 1) // node's original handler + assert.ok(err) + assert.ok(!res.headersSent) + assert.strictEqual(err.message, 'broken!') done(); }); - req.socket.emit('error', new Error('broken!')); + req.socket.destroy(new Error('broken!')) }); request(app) From 61f40491222dbede653b9938e6a4676f187aab44 Mon Sep 17 00:00:00 2001 From: Abhinav Das Date: Sat, 8 Oct 2022 00:32:42 +0530 Subject: [PATCH 17/77] docs: replace Freenode with Libera Chat closes #5013 --- Readme.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Readme.md b/Readme.md index 9b8bc34a0c..0936816bed 100644 --- a/Readme.md +++ b/Readme.md @@ -51,7 +51,7 @@ for more information. ## Docs & Community * [Website and Documentation](http://expressjs.com/) - [[website repo](https://github.com/expressjs/expressjs.com)] - * [#express](https://webchat.freenode.net/?channels=express) on freenode IRC + * [#express](https://web.libera.chat/#express) on [Libera Chat](https://libera.chat) IRC * [GitHub Organization](https://github.com/expressjs) for Official Middleware & Modules * Visit the [Wiki](https://github.com/expressjs/express/wiki) * [Google Group](https://groups.google.com/group/express-js) for discussion From 8368dc178af16b91b576c4c1d135f701a0007e5d Mon Sep 17 00:00:00 2001 From: Douglas Christopher Wilson Date: Sat, 8 Oct 2022 16:11:42 -0400 Subject: [PATCH 18/77] 4.18.2 --- History.md | 4 ++-- package.json | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/History.md b/History.md index a05baee617..e49870fed0 100644 --- a/History.md +++ b/History.md @@ -1,5 +1,5 @@ -unreleased -========== +4.18.2 / 2022-10-08 +=================== * Fix regression routing a large stack in a single route * deps: body-parser@1.20.1 diff --git a/package.json b/package.json index 6a11013c72..0996637dea 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "express", "description": "Fast, unopinionated, minimalist web framework", - "version": "4.18.1", + "version": "4.18.2", "author": "TJ Holowaychuk ", "contributors": [ "Aaron Heckmann ", From 06b2b1416d07698b8a6eed467f90d0b3ceb380c8 Mon Sep 17 00:00:00 2001 From: Kevin Jones Date: Mon, 31 Oct 2022 16:39:42 -0400 Subject: [PATCH 19/77] docs: update git clone to https protocol closes #5032 --- Readme.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Readme.md b/Readme.md index 0936816bed..d0f3cf56e6 100644 --- a/Readme.md +++ b/Readme.md @@ -104,7 +104,7 @@ $ npm start To view the examples, clone the Express repo and install the dependencies: ```console -$ git clone git://github.com/expressjs/express.git --depth 1 +$ git clone https://github.com/expressjs/express.git --depth 1 $ cd express $ npm install ``` From 29e117e676901a804031896f95f0eba317b05099 Mon Sep 17 00:00:00 2001 From: Arnaud Benhamdine Date: Tue, 1 Nov 2022 22:34:11 +0100 Subject: [PATCH 20/77] build: Node.js@16.18 --- .github/workflows/ci.yml | 2 +- appveyor.yml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index cd93ab223d..33da666df3 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -100,7 +100,7 @@ jobs: node-version: "15.14" - name: Node.js 16.x - node-version: "16.17" + node-version: "16.18" - name: Node.js 17.x node-version: "17.9" diff --git a/appveyor.yml b/appveyor.yml index 1fca21801e..5c55ace4a0 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -17,7 +17,7 @@ environment: - nodejs_version: "13.14" - nodejs_version: "14.20" - nodejs_version: "15.14" - - nodejs_version: "16.17" + - nodejs_version: "16.18" - nodejs_version: "17.9" - nodejs_version: "18.10" cache: From 723b67766fb864424a59ebe46b6516bb484f6a23 Mon Sep 17 00:00:00 2001 From: Arnaud Benhamdine Date: Tue, 1 Nov 2022 22:34:11 +0100 Subject: [PATCH 21/77] build: Node.js@18.12 --- .github/workflows/ci.yml | 2 +- appveyor.yml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 33da666df3..868525a4b1 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -106,7 +106,7 @@ jobs: node-version: "17.9" - name: Node.js 18.x - node-version: "18.10" + node-version: "18.12" steps: - uses: actions/checkout@v2 diff --git a/appveyor.yml b/appveyor.yml index 5c55ace4a0..02a5c1169d 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -19,7 +19,7 @@ environment: - nodejs_version: "15.14" - nodejs_version: "16.18" - nodejs_version: "17.9" - - nodejs_version: "18.10" + - nodejs_version: "18.12" cache: - node_modules install: From 442fd467992992558806da8da07e945838712587 Mon Sep 17 00:00:00 2001 From: Abdul Rauf Date: Wed, 19 Oct 2022 18:05:06 +0500 Subject: [PATCH 22/77] build: actions/checkout@v3 closes #5027 --- .github/workflows/ci.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 868525a4b1..b6a2879603 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -109,7 +109,7 @@ jobs: node-version: "18.12" steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@v3 - name: Install Node.js ${{ matrix.node-version }} shell: bash -eo pipefail -l {0} From c6ee8d6e7f11c3ac6bdda8e1bd4c1e38445f2d22 Mon Sep 17 00:00:00 2001 From: Rakesh Bisht Date: Fri, 10 Feb 2023 11:50:16 +0530 Subject: [PATCH 23/77] lint: remove unused function arguments in tests closes #5124 --- test/Router.js | 2 +- test/app.param.js | 6 +++--- test/app.router.js | 22 +++++++++++----------- test/res.format.js | 4 ++-- 4 files changed, 17 insertions(+), 17 deletions(-) diff --git a/test/Router.js b/test/Router.js index 0d0502ab40..620c60278a 100644 --- a/test/Router.js +++ b/test/Router.js @@ -201,7 +201,7 @@ describe('Router', function(){ it('should handle throwing inside routes with params', function(done) { var router = new Router(); - router.get('/foo/:id', function(req, res, next){ + router.get('/foo/:id', function () { throw new Error('foo'); }); diff --git a/test/app.param.js b/test/app.param.js index 8893851f9d..b4ccc8a2d1 100644 --- a/test/app.param.js +++ b/test/app.param.js @@ -166,7 +166,7 @@ describe('app', function(){ app.get('/:user', function(req, res, next) { next('route'); }); - app.get('/:user', function(req, res, next) { + app.get('/:user', function (req, res) { res.send(req.params.user); }); @@ -187,11 +187,11 @@ describe('app', function(){ next(new Error('invalid invocation')) }); - app.post('/:user', function(req, res, next) { + app.post('/:user', function (req, res) { res.send(req.params.user); }); - app.get('/:thing', function(req, res, next) { + app.get('/:thing', function (req, res) { res.send(req.thing); }); diff --git a/test/app.router.js b/test/app.router.js index 3069a22c77..4fde03105c 100644 --- a/test/app.router.js +++ b/test/app.router.js @@ -90,7 +90,7 @@ describe('app.router', function(){ it('should decode correct params', function(done){ var app = express(); - app.get('/:name', function(req, res, next){ + app.get('/:name', function (req, res) { res.send(req.params.name); }); @@ -102,7 +102,7 @@ describe('app.router', function(){ it('should not accept params in malformed paths', function(done) { var app = express(); - app.get('/:name', function(req, res, next){ + app.get('/:name', function (req, res) { res.send(req.params.name); }); @@ -114,7 +114,7 @@ describe('app.router', function(){ it('should not decode spaces', function(done) { var app = express(); - app.get('/:name', function(req, res, next){ + app.get('/:name', function (req, res) { res.send(req.params.name); }); @@ -126,7 +126,7 @@ describe('app.router', function(){ it('should work with unicode', function(done) { var app = express(); - app.get('/:name', function(req, res, next){ + app.get('/:name', function (req, res) { res.send(req.params.name); }); @@ -910,7 +910,7 @@ describe('app.router', function(){ next(); }); - app.get('/bar', function(req, res){ + app.get('/bar', function () { assert(0); }); @@ -919,7 +919,7 @@ describe('app.router', function(){ next(); }); - app.get('/foo', function(req, res, next){ + app.get('/foo', function (req, res) { calls.push('/foo 2'); res.json(calls) }); @@ -939,7 +939,7 @@ describe('app.router', function(){ next('route') } - app.get('/foo', fn, function(req, res, next){ + app.get('/foo', fn, function (req, res) { res.end('failure') }); @@ -964,11 +964,11 @@ describe('app.router', function(){ next('router') } - router.get('/foo', fn, function (req, res, next) { + router.get('/foo', fn, function (req, res) { res.end('failure') }) - router.get('/foo', function (req, res, next) { + router.get('/foo', function (req, res) { res.end('failure') }) @@ -995,7 +995,7 @@ describe('app.router', function(){ next(); }); - app.get('/bar', function(req, res){ + app.get('/bar', function () { assert(0); }); @@ -1004,7 +1004,7 @@ describe('app.router', function(){ next(new Error('fail')); }); - app.get('/foo', function(req, res, next){ + app.get('/foo', function () { assert(0); }); diff --git a/test/res.format.js b/test/res.format.js index 45243d17a1..cba6fe136b 100644 --- a/test/res.format.js +++ b/test/res.format.js @@ -61,7 +61,7 @@ app3.use(function(req, res, next){ var app4 = express(); -app4.get('/', function(req, res, next){ +app4.get('/', function (req, res) { res.format({ text: function(){ res.send('hey') }, html: function(){ res.send('

hey

') }, @@ -155,7 +155,7 @@ describe('res', function(){ var app = express(); var router = express.Router(); - router.get('/', function(req, res, next){ + router.get('/', function (req, res) { res.format({ text: function(){ res.send('hey') }, html: function(){ res.send('

hey

') }, From a1efd9d6cf968a9e863f3fdd3fef63d06ff039c4 Mon Sep 17 00:00:00 2001 From: Rakesh Bisht Date: Wed, 8 Feb 2023 16:13:20 +0530 Subject: [PATCH 24/77] lint: remove unused parameter from internal function coses #5119 --- lib/utils.js | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/lib/utils.js b/lib/utils.js index 799a6a2b4e..ab22f61e96 100644 --- a/lib/utils.js +++ b/lib/utils.js @@ -117,17 +117,15 @@ exports.contentDisposition = deprecate.function(contentDisposition, /** * Parse accept params `str` returning an * object with `.value`, `.quality` and `.params`. - * also includes `.originalIndex` for stable sorting * * @param {String} str - * @param {Number} index * @return {Object} * @api private */ -function acceptParams(str, index) { +function acceptParams (str) { var parts = str.split(/ *; */); - var ret = { value: parts[0], quality: 1, params: {}, originalIndex: index }; + var ret = { value: parts[0], quality: 1, params: {} } for (var i = 1; i < parts.length; ++i) { var pms = parts[i].split(/ *= */); From 6b4c4f5426fb5de23fb7174fd6e3bf53048e06ca Mon Sep 17 00:00:00 2001 From: Rakesh Bisht Date: Wed, 8 Feb 2023 15:56:13 +0530 Subject: [PATCH 25/77] docs: fix typos in JSDoc comments closes #5117 --- examples/markdown/index.js | 2 +- lib/router/index.js | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/examples/markdown/index.js b/examples/markdown/index.js index 74ac05e77f..23d645e66b 100644 --- a/examples/markdown/index.js +++ b/examples/markdown/index.js @@ -26,7 +26,7 @@ app.engine('md', function(path, options, fn){ app.set('views', path.join(__dirname, 'views')); -// make it the default so we dont need .md +// make it the default, so we don't need .md app.set('view engine', 'md'); app.get('/', function(req, res){ diff --git a/lib/router/index.js b/lib/router/index.js index 5174c34f45..abb3a6f589 100644 --- a/lib/router/index.js +++ b/lib/router/index.js @@ -36,7 +36,7 @@ var toString = Object.prototype.toString; * Initialize a new `Router` with the given `options`. * * @param {Object} [options] - * @return {Router} which is an callable function + * @return {Router} which is a callable function * @public */ From 3c1d605da76a6c25dbe423a42d58871803c3e328 Mon Sep 17 00:00:00 2001 From: Rakesh Bisht Date: Fri, 3 Feb 2023 20:34:39 +0530 Subject: [PATCH 26/77] lint: remove unused parameters in examples closes #5113 --- examples/error/index.js | 2 +- examples/view-locals/index.js | 4 ++-- examples/web-service/index.js | 4 ++-- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/examples/error/index.js b/examples/error/index.js index d922de06cc..d733a81172 100644 --- a/examples/error/index.js +++ b/examples/error/index.js @@ -26,7 +26,7 @@ function error(err, req, res, next) { res.send('Internal Server Error'); } -app.get('/', function(req, res){ +app.get('/', function () { // Caught and passed down to the errorHandler middleware throw new Error('something broke!'); }); diff --git a/examples/view-locals/index.js b/examples/view-locals/index.js index bf52d2a85a..a2af24f355 100644 --- a/examples/view-locals/index.js +++ b/examples/view-locals/index.js @@ -61,7 +61,7 @@ function users(req, res, next) { }) } -app.get('/middleware', count, users, function(req, res, next){ +app.get('/middleware', count, users, function (req, res) { res.render('index', { title: 'Users', count: req.count, @@ -99,7 +99,7 @@ function users2(req, res, next) { }) } -app.get('/middleware-locals', count2, users2, function(req, res, next){ +app.get('/middleware-locals', count2, users2, function (req, res) { // you can see now how we have much less // to pass to res.render(). If we have // several routes related to users this diff --git a/examples/web-service/index.js b/examples/web-service/index.js index a2cd2cb7f9..d1a9036215 100644 --- a/examples/web-service/index.js +++ b/examples/web-service/index.js @@ -72,12 +72,12 @@ var userRepos = { // and simply expose the data // example: http://localhost:3000/api/users/?api-key=foo -app.get('/api/users', function(req, res, next){ +app.get('/api/users', function (req, res) { res.send(users); }); // example: http://localhost:3000/api/repos/?api-key=foo -app.get('/api/repos', function(req, res, next){ +app.get('/api/repos', function (req, res) { res.send(repos); }); From f05b5d0e9c43625e5677b427c33b2f950eb5bea8 Mon Sep 17 00:00:00 2001 From: Douglas Christopher Wilson Date: Wed, 22 Feb 2023 11:59:40 -0500 Subject: [PATCH 27/77] build: Node.js@16.19 --- .github/workflows/ci.yml | 2 +- appveyor.yml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index b6a2879603..332ce4394c 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -100,7 +100,7 @@ jobs: node-version: "15.14" - name: Node.js 16.x - node-version: "16.18" + node-version: "16.19" - name: Node.js 17.x node-version: "17.9" diff --git a/appveyor.yml b/appveyor.yml index 02a5c1169d..4c8722ed9f 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -17,7 +17,7 @@ environment: - nodejs_version: "13.14" - nodejs_version: "14.20" - nodejs_version: "15.14" - - nodejs_version: "16.18" + - nodejs_version: "16.19" - nodejs_version: "17.9" - nodejs_version: "18.12" cache: From 546969d1989d00fda460ccb23fabb943650dac51 Mon Sep 17 00:00:00 2001 From: Douglas Christopher Wilson Date: Wed, 22 Feb 2023 12:07:48 -0500 Subject: [PATCH 28/77] build: Node.js@18.14 --- .github/workflows/ci.yml | 8 ++++++-- appveyor.yml | 8 ++++++-- 2 files changed, 12 insertions(+), 4 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 332ce4394c..64538c290c 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -106,7 +106,7 @@ jobs: node-version: "17.9" - name: Node.js 18.x - node-version: "18.12" + node-version: "18.14" steps: - uses: actions/checkout@v3 @@ -120,7 +120,11 @@ jobs: - name: Configure npm run: | npm config set loglevel error - npm config set shrinkwrap false + if [[ "$(npm config get package-lock)" == "true" ]]; then + npm config set package-lock false + else + npm config set shrinkwrap false + fi - name: Install npm module(s) ${{ matrix.npm-i }} run: npm install --save-dev ${{ matrix.npm-i }} diff --git a/appveyor.yml b/appveyor.yml index 4c8722ed9f..47941052bf 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -19,7 +19,7 @@ environment: - nodejs_version: "15.14" - nodejs_version: "16.19" - nodejs_version: "17.9" - - nodejs_version: "18.12" + - nodejs_version: "18.14" cache: - node_modules install: @@ -30,7 +30,11 @@ install: # Configure npm - ps: | npm config set loglevel error - npm config set shrinkwrap false + if ((npm config get package-lock) -eq "true") { + npm config set package-lock false + } else { + npm config set shrinkwrap false + } # Remove all non-test dependencies - ps: | # Remove example dependencies From b9f7a97fe164d2a64279105abe375c69eaab9ebb Mon Sep 17 00:00:00 2001 From: Douglas Christopher Wilson Date: Wed, 22 Feb 2023 18:10:59 -0500 Subject: [PATCH 29/77] build: use $GITHUB_OUTPUT for environment list --- .github/workflows/ci.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 64538c290c..a4bf538948 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -155,7 +155,7 @@ jobs: echo "node@$(node -v)" echo "npm@$(npm -v)" npm -s ls ||: - (npm -s ls --depth=0 ||:) | awk -F'[ @]' 'NR>1 && $2 { print "::set-output name=" $2 "::" $3 }' + (npm -s ls --depth=0 ||:) | awk -F'[ @]' 'NR>1 && $2 { print $2 "=" $3 }' >> "$GITHUB_OUTPUT" - name: Run tests shell: bash From 506fbd63befe810783dba49d11159c7ad46c239a Mon Sep 17 00:00:00 2001 From: Rakesh Bisht Date: Wed, 22 Feb 2023 18:30:50 +0530 Subject: [PATCH 30/77] docs: add missing JSDoc param for parseExtendedQueryString closes #5130 --- lib/utils.js | 1 + 1 file changed, 1 insertion(+) diff --git a/lib/utils.js b/lib/utils.js index ab22f61e96..56e12b9b54 100644 --- a/lib/utils.js +++ b/lib/utils.js @@ -280,6 +280,7 @@ function createETagGenerator (options) { /** * Parse an extended query string with qs. * + * @param {String} str * @return {Object} * @private */ From 1e42a98db6708e5a3609d0f7c09bcc176b481ea7 Mon Sep 17 00:00:00 2001 From: Douglas Christopher Wilson Date: Thu, 23 Feb 2023 00:24:20 -0500 Subject: [PATCH 31/77] deps: body-parser@1.20.2 --- History.md | 8 ++++++++ package.json | 2 +- test/express.json.js | 8 ++++---- 3 files changed, 13 insertions(+), 5 deletions(-) diff --git a/History.md b/History.md index e49870fed0..7b0cc4abf7 100644 --- a/History.md +++ b/History.md @@ -1,3 +1,11 @@ +unreleased +========== + + * deps: body-parser@1.20.2 + - Fix strict json error message on Node.js 19+ + - deps: content-type@~1.0.5 + - deps: raw-body@2.5.2 + 4.18.2 / 2022-10-08 =================== diff --git a/package.json b/package.json index 0996637dea..adf479dfce 100644 --- a/package.json +++ b/package.json @@ -30,7 +30,7 @@ "dependencies": { "accepts": "~1.3.8", "array-flatten": "1.1.1", - "body-parser": "1.20.1", + "body-parser": "1.20.2", "content-disposition": "0.5.4", "content-type": "~1.0.4", "cookie": "0.5.0", diff --git a/test/express.json.js b/test/express.json.js index a8cfebc41e..f6f536b15e 100644 --- a/test/express.json.js +++ b/test/express.json.js @@ -262,7 +262,7 @@ describe('express.json()', function () { .post('/') .set('Content-Type', 'application/json') .send('true') - .expect(400, '[entity.parse.failed] ' + parseError('#rue').replace('#', 't'), done) + .expect(400, '[entity.parse.failed] ' + parseError('#rue').replace(/#/g, 't'), done) }) }) @@ -290,7 +290,7 @@ describe('express.json()', function () { .post('/') .set('Content-Type', 'application/json') .send('true') - .expect(400, '[entity.parse.failed] ' + parseError('#rue').replace('#', 't'), done) + .expect(400, '[entity.parse.failed] ' + parseError('#rue').replace(/#/g, 't'), done) }) it('should not parse primitives with leading whitespaces', function (done) { @@ -298,7 +298,7 @@ describe('express.json()', function () { .post('/') .set('Content-Type', 'application/json') .send(' true') - .expect(400, '[entity.parse.failed] ' + parseError(' #rue').replace('#', 't'), done) + .expect(400, '[entity.parse.failed] ' + parseError(' #rue').replace(/#/g, 't'), done) }) it('should allow leading whitespaces in JSON', function (done) { @@ -316,7 +316,7 @@ describe('express.json()', function () { .set('X-Error-Property', 'stack') .send('true') .expect(400) - .expect(shouldContainInBody(parseError('#rue').replace('#', 't'))) + .expect(shouldContainInBody(parseError('#rue').replace(/#/g, 't'))) .end(done) }) }) From 60b7c672c19ba6b96cc7e5383eee00f8bf99a45a Mon Sep 17 00:00:00 2001 From: Douglas Christopher Wilson Date: Thu, 23 Feb 2023 00:27:06 -0500 Subject: [PATCH 32/77] build: mocha@10.2.0 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index adf479dfce..c3641a02c8 100644 --- a/package.json +++ b/package.json @@ -71,7 +71,7 @@ "hbs": "4.2.0", "marked": "0.7.0", "method-override": "3.0.0", - "mocha": "10.0.0", + "mocha": "10.2.0", "morgan": "1.10.0", "multiparty": "4.2.3", "nyc": "15.1.0", From 8a76f39d9844f36797cd794fb74b47c635798ae5 Mon Sep 17 00:00:00 2001 From: Douglas Christopher Wilson Date: Thu, 23 Feb 2023 00:28:41 -0500 Subject: [PATCH 33/77] build: eslint@8.34.0 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index c3641a02c8..e4ed037cfa 100644 --- a/package.json +++ b/package.json @@ -66,7 +66,7 @@ "cookie-parser": "1.4.6", "cookie-session": "2.0.0", "ejs": "3.1.8", - "eslint": "8.24.0", + "eslint": "8.34.0", "express-session": "1.17.2", "hbs": "4.2.0", "marked": "0.7.0", From 5ad95419bac1cb5bcc1f09fd1872f2b2af4aed1a Mon Sep 17 00:00:00 2001 From: Rakesh Bisht Date: Thu, 23 Feb 2023 11:36:40 +0530 Subject: [PATCH 34/77] docs: fix typos in history closes #5131 --- History.md | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/History.md b/History.md index 7b0cc4abf7..17b03705df 100644 --- a/History.md +++ b/History.md @@ -2119,7 +2119,7 @@ unreleased * deps: connect@2.21.0 - deprecate `connect(middleware)` -- use `app.use(middleware)` instead - deprecate `connect.createServer()` -- use `connect()` instead - - fix `res.setHeader()` patch to work with with get -> append -> set pattern + - fix `res.setHeader()` patch to work with get -> append -> set pattern - deps: compression@~1.0.8 - deps: errorhandler@~1.1.1 - deps: express-session@~1.5.0 @@ -3330,8 +3330,8 @@ Shaw] * Added node v0.1.97 compatibility * Added support for deleting cookies via Request#cookie('key', null) * Updated haml submodule - * Fixed not-found page, now using using charset utf-8 - * Fixed show-exceptions page, now using using charset utf-8 + * Fixed not-found page, now using charset utf-8 + * Fixed show-exceptions page, now using charset utf-8 * Fixed view support due to fs.readFile Buffers * Changed; mime.type() no longer accepts ".type" due to node extname() changes @@ -3366,7 +3366,7 @@ Shaw] ================== * Added charset support via Request#charset (automatically assigned to 'UTF-8' when respond()'s - encoding is set to 'utf8' or 'utf-8'. + encoding is set to 'utf8' or 'utf-8'). * Added "encoding" option to Request#render(). Closes #299 * Added "dump exceptions" setting, which is enabled by default. * Added simple ejs template engine support @@ -3405,7 +3405,7 @@ Shaw] * Added [haml.js](http://github.com/visionmedia/haml.js) submodule; removed haml-js * Added callback function support to Request#halt() as 3rd/4th arg * Added preprocessing of route param wildcards using param(). Closes #251 - * Added view partial support (with collections etc) + * Added view partial support (with collections etc.) * Fixed bug preventing falsey params (such as ?page=0). Closes #286 * Fixed setting of multiple cookies. Closes #199 * Changed; view naming convention is now NAME.TYPE.ENGINE (for example page.html.haml) From 9bc1742937253825d2dc1e9a48c8e8424f0a315b Mon Sep 17 00:00:00 2001 From: Arnaud Benhamdine Date: Thu, 23 Feb 2023 14:18:57 +0100 Subject: [PATCH 35/77] build: support Node.js 19.x --- .github/workflows/ci.yml | 4 ++++ appveyor.yml | 1 + 2 files changed, 5 insertions(+) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index a4bf538948..c6fb81de93 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -31,6 +31,7 @@ jobs: - Node.js 16.x - Node.js 17.x - Node.js 18.x + - Node.js 19.x include: - name: Node.js 0.10 @@ -108,6 +109,9 @@ jobs: - name: Node.js 18.x node-version: "18.14" + - name: Node.js 19.x + node-version: "19.7" + steps: - uses: actions/checkout@v3 diff --git a/appveyor.yml b/appveyor.yml index 47941052bf..ac671ef47b 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -20,6 +20,7 @@ environment: - nodejs_version: "16.19" - nodejs_version: "17.9" - nodejs_version: "18.14" + - nodejs_version: "19.7" cache: - node_modules install: From 74beeac0718c928b4ba249aba3652c52fbe32ca8 Mon Sep 17 00:00:00 2001 From: Douglas Christopher Wilson Date: Thu, 23 Feb 2023 17:23:22 -0500 Subject: [PATCH 36/77] Fix routing requests without method --- History.md | 1 + lib/router/route.js | 9 +++++++-- test/Router.js | 27 +++++++++++++++++++++++++++ 3 files changed, 35 insertions(+), 2 deletions(-) diff --git a/History.md b/History.md index 17b03705df..9e85df3ceb 100644 --- a/History.md +++ b/History.md @@ -1,6 +1,7 @@ unreleased ========== + * Fix routing requests without method * deps: body-parser@1.20.2 - Fix strict json error message on Node.js 19+ - deps: content-type@~1.0.5 diff --git a/lib/router/route.js b/lib/router/route.js index cc643ac8bd..a65756d6de 100644 --- a/lib/router/route.js +++ b/lib/router/route.js @@ -60,7 +60,10 @@ Route.prototype._handles_method = function _handles_method(method) { return true; } - var name = method.toLowerCase(); + // normalize name + var name = typeof method === 'string' + ? method.toLowerCase() + : method if (name === 'head' && !this.methods['head']) { name = 'get'; @@ -103,8 +106,10 @@ Route.prototype.dispatch = function dispatch(req, res, done) { if (stack.length === 0) { return done(); } + var method = typeof req.method === 'string' + ? req.method.toLowerCase() + : req.method - var method = req.method.toLowerCase(); if (method === 'head' && !this.methods['head']) { method = 'get'; } diff --git a/test/Router.js b/test/Router.js index 620c60278a..cf5b5c1f0d 100644 --- a/test/Router.js +++ b/test/Router.js @@ -61,6 +61,33 @@ describe('Router', function(){ router.handle({ method: 'GET' }, {}, done) }) + it('handle missing method', function (done) { + var all = false + var router = new Router() + var route = router.route('/foo') + var use = false + + route.post(function (req, res, next) { next(new Error('should not run')) }) + route.all(function (req, res, next) { + all = true + next() + }) + route.get(function (req, res, next) { next(new Error('should not run')) }) + + router.get('/foo', function (req, res, next) { next(new Error('should not run')) }) + router.use(function (req, res, next) { + use = true + next() + }) + + router.handle({ url: '/foo' }, {}, function (err) { + if (err) return done(err) + assert.ok(all) + assert.ok(use) + done() + }) + }) + it('should not stack overflow with many registered routes', function(done){ this.timeout(5000) // long-running test From 0debedf4f31bb20203da0534719b9b10d6ac9a29 Mon Sep 17 00:00:00 2001 From: Douglas Christopher Wilson Date: Sun, 26 Feb 2023 13:34:32 -0500 Subject: [PATCH 37/77] build: fix code coverage aggregate upload --- .github/workflows/ci.yml | 39 +++++++++++++++++++++++++++++++-------- 1 file changed, 31 insertions(+), 8 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index c6fb81de93..b30c56c2f1 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -163,25 +163,48 @@ jobs: - name: Run tests shell: bash - run: npm run test-ci + run: | + npm run test-ci + cp coverage/lcov.info "coverage/${{ matrix.name }}.lcov" - name: Lint code if: steps.list_env.outputs.eslint != '' run: npm run lint - name: Collect code coverage - uses: coverallsapp/github-action@master + run: | + mv ./coverage "./${{ matrix.name }}" + mkdir ./coverage + mv "./${{ matrix.name }}" "./coverage/${{ matrix.name }}" + + - name: Upload code coverage + uses: actions/upload-artifact@v3 with: - github-token: ${{ secrets.GITHUB_TOKEN }} - flag-name: run-${{ matrix.test_number }} - parallel: true + name: coverage + path: ./coverage + retention-days: 1 coverage: needs: test runs-on: ubuntu-latest steps: - - name: Upload code coverage + - uses: actions/checkout@v3 + + - name: Install lcov + shell: bash + run: sudo apt-get -y install lcov + + - name: Collect coverage reports + uses: actions/download-artifact@v3 + with: + name: coverage + path: ./coverage + + - name: Merge coverage reports + shell: bash + run: find ./coverage -name lcov.info -exec printf '-a %q\n' {} \; | xargs lcov -o ./coverage/lcov.info + + - name: Upload coverage report uses: coverallsapp/github-action@master with: - github-token: ${{ secrets.github_token }} - parallel-finished: true + github-token: ${{ secrets.GITHUB_TOKEN }} From 8c24fa8f7b6d443869c655166c93869d8b299627 Mon Sep 17 00:00:00 2001 From: Douglas Christopher Wilson Date: Mon, 13 Mar 2023 22:43:19 -0400 Subject: [PATCH 38/77] tests: wait for server close in app.listen() --- test/app.listen.js | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/test/app.listen.js b/test/app.listen.js index 08eeaaa63c..0eec582e69 100644 --- a/test/app.listen.js +++ b/test/app.listen.js @@ -7,8 +7,7 @@ describe('app.listen()', function(){ var app = express(); var server = app.listen(9999, function(){ - server.close(); - done(); + server.close(done) }); }) }) From f4e48bc43eece928f005a4458c87a16ce089e8e5 Mon Sep 17 00:00:00 2001 From: Douglas Christopher Wilson Date: Mon, 13 Mar 2023 22:49:54 -0400 Subject: [PATCH 39/77] build: ejs@3.1.9 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index e4ed037cfa..8a7548aff5 100644 --- a/package.json +++ b/package.json @@ -65,7 +65,7 @@ "connect-redis": "3.4.2", "cookie-parser": "1.4.6", "cookie-session": "2.0.0", - "ejs": "3.1.8", + "ejs": "3.1.9", "eslint": "8.34.0", "express-session": "1.17.2", "hbs": "4.2.0", From b8b2eff3c3eac6a1df3919a87f7c7316d40ae97a Mon Sep 17 00:00:00 2001 From: Douglas Christopher Wilson Date: Mon, 13 Mar 2023 22:52:34 -0400 Subject: [PATCH 40/77] build: eslint@8.36.0 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 8a7548aff5..b77937d439 100644 --- a/package.json +++ b/package.json @@ -66,7 +66,7 @@ "cookie-parser": "1.4.6", "cookie-session": "2.0.0", "ejs": "3.1.9", - "eslint": "8.34.0", + "eslint": "8.36.0", "express-session": "1.17.2", "hbs": "4.2.0", "marked": "0.7.0", From f540c3b0195393974d4875a410f4c00a07a2ab60 Mon Sep 17 00:00:00 2001 From: Douglas Christopher Wilson Date: Mon, 13 Mar 2023 22:59:15 -0400 Subject: [PATCH 41/77] build: Node.js@18.15 --- .github/workflows/ci.yml | 2 +- appveyor.yml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index b30c56c2f1..20c37976a4 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -107,7 +107,7 @@ jobs: node-version: "17.9" - name: Node.js 18.x - node-version: "18.14" + node-version: "18.15" - name: Node.js 19.x node-version: "19.7" diff --git a/appveyor.yml b/appveyor.yml index ac671ef47b..e9a6e6d57e 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -19,7 +19,7 @@ environment: - nodejs_version: "15.14" - nodejs_version: "16.19" - nodejs_version: "17.9" - - nodejs_version: "18.14" + - nodejs_version: "18.15" - nodejs_version: "19.7" cache: - node_modules From 3531987844e533742f1159b0c3f1e07fad2e4597 Mon Sep 17 00:00:00 2001 From: Rakesh Bisht Date: Sat, 4 Mar 2023 13:48:00 +0530 Subject: [PATCH 42/77] lint: remove unused function arguments in Route tests closes #5137 --- test/Route.js | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/test/Route.js b/test/Route.js index 64dbad60ce..2a37b9a483 100644 --- a/test/Route.js +++ b/test/Route.js @@ -124,7 +124,7 @@ describe('Route', function(){ var req = { method: 'POST', url: '/' }; var route = new Route(''); - route.get(function(req, res, next) { + route.get(function () { throw new Error('not me!'); }) @@ -198,7 +198,7 @@ describe('Route', function(){ var req = { order: '', method: 'GET', url: '/' }; var route = new Route(''); - route.all(function(req, res, next){ + route.all(function () { throw new Error('foobar'); }); @@ -224,7 +224,7 @@ describe('Route', function(){ var req = { method: 'GET', url: '/' }; var route = new Route(''); - route.get(function(req, res, next){ + route.get(function () { throw new Error('boom!'); }); From 91b6fb83b4cf30ec626c0582f0b3a0a98d8afcb4 Mon Sep 17 00:00:00 2001 From: Douglas Christopher Wilson Date: Thu, 6 Apr 2023 20:40:27 -0400 Subject: [PATCH 43/77] build: use nyc@14.1.1 for Node.js < 10 --- .github/workflows/ci.yml | 4 ++-- appveyor.yml | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 20c37976a4..856c6314e8 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -72,11 +72,11 @@ jobs: - name: Node.js 8.x node-version: "8.17" - npm-i: mocha@7.2.0 + npm-i: mocha@7.2.0 nyc@14.1.1 - name: Node.js 9.x node-version: "9.11" - npm-i: mocha@7.2.0 + npm-i: mocha@7.2.0 nyc@14.1.1 - name: Node.js 10.x node-version: "10.24" diff --git a/appveyor.yml b/appveyor.yml index e9a6e6d57e..88e81dfeee 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -70,12 +70,12 @@ install: # nyc for test coverage # - use 10.3.2 for Node.js < 4 # - use 11.9.0 for Node.js < 6 - # - use 14.1.1 for Node.js < 8 + # - use 14.1.1 for Node.js < 10 if ([int]$env:nodejs_version.split(".")[0] -lt 4) { npm install --silent --save-dev nyc@10.3.2 } elseif ([int]$env:nodejs_version.split(".")[0] -lt 6) { npm install --silent --save-dev nyc@11.9.0 - } elseif ([int]$env:nodejs_version.split(".")[0] -lt 8) { + } elseif ([int]$env:nodejs_version.split(".")[0] -lt 10) { npm install --silent --save-dev nyc@14.1.1 } - ps: | From 24e4a2570d15d6cca53023410f754929c5391c6f Mon Sep 17 00:00:00 2001 From: Douglas Christopher Wilson Date: Thu, 6 Apr 2023 20:43:53 -0400 Subject: [PATCH 44/77] build: Node.js@16.20 --- .github/workflows/ci.yml | 2 +- appveyor.yml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 856c6314e8..30767d9896 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -101,7 +101,7 @@ jobs: node-version: "15.14" - name: Node.js 16.x - node-version: "16.19" + node-version: "16.20" - name: Node.js 17.x node-version: "17.9" diff --git a/appveyor.yml b/appveyor.yml index 88e81dfeee..1412811ff4 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -17,7 +17,7 @@ environment: - nodejs_version: "13.14" - nodejs_version: "14.20" - nodejs_version: "15.14" - - nodejs_version: "16.19" + - nodejs_version: "16.20" - nodejs_version: "17.9" - nodejs_version: "18.15" - nodejs_version: "19.7" From 2a00da2067b7017f769c9100205a2a5f267a884b Mon Sep 17 00:00:00 2001 From: Raz Luvaton <16746759+rluvaton@users.noreply.github.com> Date: Tue, 11 Apr 2023 15:31:47 +0300 Subject: [PATCH 45/77] tests: use random port in listen test closes #5162 --- test/app.listen.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/app.listen.js b/test/app.listen.js index 0eec582e69..5b150063b9 100644 --- a/test/app.listen.js +++ b/test/app.listen.js @@ -6,7 +6,7 @@ describe('app.listen()', function(){ it('should wrap with an HTTP server', function(done){ var app = express(); - var server = app.listen(9999, function(){ + var server = app.listen(0, function () { server.close(done) }); }) From 13df1de857688057f3c7e6d315321b19f8e4259e Mon Sep 17 00:00:00 2001 From: Douglas Christopher Wilson Date: Wed, 23 Aug 2023 19:49:36 -0400 Subject: [PATCH 46/77] build: eslint@8.47.0 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index b77937d439..fdf81725b4 100644 --- a/package.json +++ b/package.json @@ -66,7 +66,7 @@ "cookie-parser": "1.4.6", "cookie-session": "2.0.0", "ejs": "3.1.9", - "eslint": "8.36.0", + "eslint": "8.47.0", "express-session": "1.17.2", "hbs": "4.2.0", "marked": "0.7.0", From 8d8bfaac7be5d06c0a8fcc069b1ee5b0ec398cd9 Mon Sep 17 00:00:00 2001 From: Douglas Christopher Wilson Date: Wed, 23 Aug 2023 19:58:41 -0400 Subject: [PATCH 47/77] build: Node.js@18.17 --- .github/workflows/ci.yml | 2 +- appveyor.yml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 30767d9896..3d14976a9b 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -107,7 +107,7 @@ jobs: node-version: "17.9" - name: Node.js 18.x - node-version: "18.15" + node-version: "18.17" - name: Node.js 19.x node-version: "19.7" diff --git a/appveyor.yml b/appveyor.yml index 1412811ff4..63adc423c8 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -19,7 +19,7 @@ environment: - nodejs_version: "15.14" - nodejs_version: "16.20" - nodejs_version: "17.9" - - nodejs_version: "18.15" + - nodejs_version: "18.17" - nodejs_version: "19.7" cache: - node_modules From 02d1c3916ebaec776b4d754be54aa1500e2e9563 Mon Sep 17 00:00:00 2001 From: Douglas Christopher Wilson Date: Wed, 23 Aug 2023 20:07:50 -0400 Subject: [PATCH 48/77] build: Node.js@19.9 --- .github/workflows/ci.yml | 2 +- appveyor.yml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 3d14976a9b..3501778533 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -110,7 +110,7 @@ jobs: node-version: "18.17" - name: Node.js 19.x - node-version: "19.7" + node-version: "19.9" steps: - uses: actions/checkout@v3 diff --git a/appveyor.yml b/appveyor.yml index 63adc423c8..44af842e85 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -20,7 +20,7 @@ environment: - nodejs_version: "16.20" - nodejs_version: "17.9" - nodejs_version: "18.17" - - nodejs_version: "19.7" + - nodejs_version: "19.9" cache: - node_modules install: From a22920707bfd30e083e5b8e076841d226266cb06 Mon Sep 17 00:00:00 2001 From: Douglas Christopher Wilson Date: Wed, 1 Nov 2023 22:08:37 -0400 Subject: [PATCH 49/77] build: actions/checkout@v4 --- .github/workflows/ci.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 3501778533..b545e8bd0d 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -113,7 +113,7 @@ jobs: node-version: "19.9" steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 - name: Install Node.js ${{ matrix.node-version }} shell: bash -eo pipefail -l {0} @@ -188,7 +188,7 @@ jobs: needs: test runs-on: ubuntu-latest steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 - name: Install lcov shell: bash From c4fe7de7bcb7ce241dfa7137fad96d48b75e86f3 Mon Sep 17 00:00:00 2001 From: Wes Todd Date: Fri, 16 Feb 2024 08:52:09 -0600 Subject: [PATCH 50/77] docs: update TC governance rules closes #5483 --- Contributing.md | 21 ++++++++++++++++++--- 1 file changed, 18 insertions(+), 3 deletions(-) diff --git a/Contributing.md b/Contributing.md index 485dee597e..89f9280632 100644 --- a/Contributing.md +++ b/Contributing.md @@ -107,7 +107,22 @@ move forward towards a consensus. It is not expected that a meeting of the TC will resolve all issues on its agenda during that meeting and may prefer to continue the discussion happening among the committers. -Members can be added to the TC at any time. Any committer can nominate another committer +Members can be added to the TC at any time. Any TC member can nominate another committer to the TC and the TC uses its standard consensus seeking process to evaluate whether or -not to add this new member. Members who do not participate consistently at the level of -a majority of the other members are expected to resign. +not to add this new member. The TC will consist of a minimum of 3 active members and a +maximum of 10. If the TC should drop below 5 members the active TC members should nominate +someone new. If a TC member is stepping down, they are encouraged (but not required) to +nominate someone to take their place. + +TC members will be added as admin's on the Github orgs, npm orgs, and other resources as +necessary to be effective in the role. + +To remain "active" a TC member should have participation within the last 6 months and miss +no more than three consecutive TC meetings. Members who do not meet this are expected to step down. +If A TC member does not step down, an issue can be opened in the discussions repo to move them +to inactive status. TC members who step down or are removed due to inactivity will be moved +into inactive status. + +Inactive status members can become active members by self nomination if the TC is not already +larger than the maximum of 10. They will also be given preference if, while at max size, an +active member steps down. From 59aae7686b995186a71da48abd4af5be72ff4ef5 Mon Sep 17 00:00:00 2001 From: Gireesh Punathil Date: Mon, 9 Mar 2020 14:12:29 +0530 Subject: [PATCH 51/77] docs: add project captains to contribution closes #4210 closes #5484 --- Contributing.md | 38 +++++++++++++++++++++++++++++++++++--- 1 file changed, 35 insertions(+), 3 deletions(-) diff --git a/Contributing.md b/Contributing.md index 89f9280632..dfe5f13833 100644 --- a/Contributing.md +++ b/Contributing.md @@ -12,6 +12,7 @@ contributors can be involved in decision making. * A **Contributor** is any individual creating or commenting on an issue or pull request. * A **Committer** is a subset of contributors who have been given write access to the repository. +* A **Project Captain** is the lead maintainer of a repository. * A **TC (Technical Committee)** is a group of committers representing the required technical expertise to resolve rare disputes. * A **Triager** is a subset of contributors who have been given triage access to the repository. @@ -102,10 +103,10 @@ If a consensus cannot be reached that has no objections then a majority wins vot is called. It is also expected that the majority of decisions made by the TC are via a consensus seeking process and that voting is only used as a last-resort. -Resolution may involve returning the issue to committers with suggestions on how to -move forward towards a consensus. It is not expected that a meeting of the TC +Resolution may involve returning the issue to project captains with suggestions on +how to move forward towards a consensus. It is not expected that a meeting of the TC will resolve all issues on its agenda during that meeting and may prefer to continue -the discussion happening among the committers. +the discussion happening among the project captains. Members can be added to the TC at any time. Any TC member can nominate another committer to the TC and the TC uses its standard consensus seeking process to evaluate whether or @@ -126,3 +127,34 @@ into inactive status. Inactive status members can become active members by self nomination if the TC is not already larger than the maximum of 10. They will also be given preference if, while at max size, an active member steps down. + +## Project Captains + +The Express TC can designate captains for individual projects/repos in the +organizations. These captains are responsible for being the primary +day-to-day maintainers of the repo on a technical and community front. +Repo captains are empowered with repo ownership and package publication rights. +When there are conflicts, especially on topics that effect the Express project +at large, captains are responsible to raise it up to the TC and drive +those conflicts to resolution. Captains are also responsible for making sure +community members follow the community guidelines, maintaining the repo +and the published package, as well as in providing user support. + +Like TC members, Repo captains are a subset of committers. + +To become a captain for a project the candidate is expected to participate in that +project for at least 6 months as a committer prior to the request. They should have +helped with code contributions as well as triaging issues. They are also required to +have 2FA enabled on both their GitHub and npm accounts. Any TC member or existing +captain on the repo can nominate another committer to the captain role, submit a PR to +this doc, under `Current Project Captains` section (maintaining the sort order) with +the project, their GitHub handle and npm username (if different). The PR will require +at least 2 approvals from TC members and 2 weeks hold time to allow for comment and/or +dissent. When the PR is merged, a TC member will add them to the proper GitHub/npm groups. + +### Current Project Captains + +- `expressjs.com`: @crandmck +- `multer`: @LinusU +- `path-to-regexp`: @blakeembrey +- `router`: @dougwilson From 2a89eb5c749a168820d6ea96723ad8a7e979a58b Mon Sep 17 00:00:00 2001 From: christof louw Date: Thu, 27 Jul 2023 11:06:18 +0200 Subject: [PATCH 52/77] tests: fix handling multiple callbacks closes #5233 --- test/Router.js | 6 +++--- test/app.router.js | 2 +- test/app.use.js | 2 +- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/test/Router.js b/test/Router.js index cf5b5c1f0d..b22001a9ff 100644 --- a/test/Router.js +++ b/test/Router.js @@ -606,8 +606,8 @@ describe('Router', function(){ var req2 = { url: '/foo/10/bar', method: 'get' }; var router = new Router(); var sub = new Router(); + var cb = after(2, done) - done = after(2, done); sub.get('/bar', function(req, res, next) { next(); @@ -626,14 +626,14 @@ describe('Router', function(){ assert.ifError(err); assert.equal(req1.ms, 50); assert.equal(req1.originalUrl, '/foo/50/bar'); - done(); + cb() }); router.handle(req2, {}, function(err) { assert.ifError(err); assert.equal(req2.ms, 10); assert.equal(req2.originalUrl, '/foo/10/bar'); - done(); + cb() }); }); }); diff --git a/test/app.router.js b/test/app.router.js index 4fde03105c..12b6c1fa51 100644 --- a/test/app.router.js +++ b/test/app.router.js @@ -896,7 +896,7 @@ describe('app.router', function(){ request(app) .get('/foo.json') - .expect(200, 'foo as json', done) + .expect(200, 'foo as json', cb) }) }) diff --git a/test/app.use.js b/test/app.use.js index fd9b1751a3..1de3275c8e 100644 --- a/test/app.use.js +++ b/test/app.use.js @@ -57,7 +57,7 @@ describe('app', function(){ request(app) .get('/forum') - .expect(200, 'forum', done) + .expect(200, 'forum', cb) }) it('should set the child\'s .parent', function(){ From 3abea7f8189c73f7f219d8878343d961eb9a4910 Mon Sep 17 00:00:00 2001 From: riddlew Date: Thu, 18 May 2023 09:26:47 -0400 Subject: [PATCH 53/77] examples: remove multipart example Closes #5193 closes #5195 --- examples/README.md | 1 - examples/multipart/index.js | 62 ------------------------------------- package.json | 1 - 3 files changed, 64 deletions(-) delete mode 100644 examples/multipart/index.js diff --git a/examples/README.md b/examples/README.md index c19ed30a25..bd1f1f6310 100644 --- a/examples/README.md +++ b/examples/README.md @@ -13,7 +13,6 @@ This page contains list of examples using Express. - [hello-world](./hello-world) - Simple request handler - [markdown](./markdown) - Markdown as template engine - [multi-router](./multi-router) - Working with multiple Express routers -- [multipart](./multipart) - Accepting multipart-encoded forms - [mvc](./mvc) - MVC-style controllers - [online](./online) - Tracking online user activity with `online` and `redis` packages - [params](./params) - Working with route parameters diff --git a/examples/multipart/index.js b/examples/multipart/index.js deleted file mode 100644 index ea7b86e0c9..0000000000 --- a/examples/multipart/index.js +++ /dev/null @@ -1,62 +0,0 @@ -'use strict' - -/** - * Module dependencies. - */ - -var express = require('../..'); -var multiparty = require('multiparty'); -var format = require('util').format; - -var app = module.exports = express(); - -app.get('/', function(req, res){ - res.send('
' - + '

Title:

' - + '

Image:

' - + '

' - + '
'); -}); - -app.post('/', function(req, res, next){ - // create a form to begin parsing - var form = new multiparty.Form(); - var image; - var title; - - form.on('error', next); - form.on('close', function(){ - res.send(format('\nuploaded %s (%d Kb) as %s' - , image.filename - , image.size / 1024 | 0 - , title)); - }); - - // listen on field event for title - form.on('field', function(name, val){ - if (name !== 'title') return; - title = val; - }); - - // listen on part event for image file - form.on('part', function(part){ - if (!part.filename) return; - if (part.name !== 'image') return part.resume(); - image = {}; - image.filename = part.filename; - image.size = 0; - part.on('data', function(buf){ - image.size += buf.length; - }); - }); - - - // parse the form - form.parse(req); -}); - -/* istanbul ignore next */ -if (!module.parent) { - app.listen(4000); - console.log('Express started on port 4000'); -} diff --git a/package.json b/package.json index fdf81725b4..cf36773643 100644 --- a/package.json +++ b/package.json @@ -73,7 +73,6 @@ "method-override": "3.0.0", "mocha": "10.2.0", "morgan": "1.10.0", - "multiparty": "4.2.3", "nyc": "15.1.0", "pbkdf2-password": "1.2.1", "supertest": "6.3.0", From e720c5a21bfed5a9c73b2407797023bacad6980e Mon Sep 17 00:00:00 2001 From: Ulises Gascon Date: Sat, 11 Nov 2023 20:02:47 +0100 Subject: [PATCH 54/77] docs: add documentation for benchmarks closes #5312 --- benchmarks/README.md | 34 ++++++++++++++++++++++++++++++++++ 1 file changed, 34 insertions(+) create mode 100644 benchmarks/README.md diff --git a/benchmarks/README.md b/benchmarks/README.md new file mode 100644 index 0000000000..1894c527d6 --- /dev/null +++ b/benchmarks/README.md @@ -0,0 +1,34 @@ +# Express Benchmarks + +## Installation + +You will need to install [wrk](https://github.com/wg/wrk/blob/master/INSTALL) in order to run the benchmarks. + +## Running + +To run the benchmarks, first install the dependencies `npm i`, then run `make` + +The output will look something like this: + +``` + 50 connections + 1 middleware + 7.15ms + 6784.01 + + [...redacted...] + + 1000 connections + 10 middleware + 139.21ms + 6155.19 + +``` + +### Tip: Include Node.js version in output + +You can use `make && node -v` to include the node.js version in the output. + +### Tip: Save the results to a file + +You can use `make > results.log` to save the results to a file `results.log`. From 59af63ac2e6aea6a9cefb6fe27705ccf024d8373 Mon Sep 17 00:00:00 2001 From: Ulises Gascon Date: Sat, 17 Feb 2024 18:26:40 +0100 Subject: [PATCH 55/77] build: Node.js@18.19 closes #5490 --- .github/workflows/ci.yml | 2 +- appveyor.yml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index b545e8bd0d..5bef1f67ed 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -107,7 +107,7 @@ jobs: node-version: "17.9" - name: Node.js 18.x - node-version: "18.17" + node-version: "18.19" - name: Node.js 19.x node-version: "19.9" diff --git a/appveyor.yml b/appveyor.yml index 44af842e85..b865082930 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -19,7 +19,7 @@ environment: - nodejs_version: "15.14" - nodejs_version: "16.20" - nodejs_version: "17.9" - - nodejs_version: "18.17" + - nodejs_version: "18.19" - nodejs_version: "19.9" cache: - node_modules From 0e3ab6ec215fc297473323fb1e8d0df03033e774 Mon Sep 17 00:00:00 2001 From: Dmitry Kondar Date: Sat, 27 Jan 2024 20:29:09 +0200 Subject: [PATCH 56/77] examples: improve view count in cookie-sessions closes #5414 --- examples/cookie-sessions/index.js | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/examples/cookie-sessions/index.js b/examples/cookie-sessions/index.js index 01c731c1c8..83b6faee82 100644 --- a/examples/cookie-sessions/index.js +++ b/examples/cookie-sessions/index.js @@ -13,13 +13,10 @@ var app = module.exports = express(); app.use(cookieSession({ secret: 'manny is cool' })); // do something with the session -app.use(count); - -// custom middleware -function count(req, res) { +app.get('/', function (req, res) { req.session.count = (req.session.count || 0) + 1 res.send('viewed ' + req.session.count + ' times\n') -} +}) /* istanbul ignore next */ if (!module.parent) { From 734b28190085c052e3ecd9c7d0b9595d9edb1b85 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ulises=20Gasc=C3=B3n?= Date: Fri, 2 Feb 2024 15:35:20 +0100 Subject: [PATCH 57/77] build: support Node.js 20.x --- .github/workflows/ci.yml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 5bef1f67ed..df123370d9 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -32,6 +32,7 @@ jobs: - Node.js 17.x - Node.js 18.x - Node.js 19.x + - Node.js 20.x include: - name: Node.js 0.10 @@ -112,6 +113,8 @@ jobs: - name: Node.js 19.x node-version: "19.9" + - name: Node.js 20.x + node-version: "20.11" steps: - uses: actions/checkout@v4 From fdeb1d3176d11506557388ecaa2fe6a250e17efc Mon Sep 17 00:00:00 2001 From: Ulises Gascon Date: Fri, 2 Feb 2024 16:31:12 +0100 Subject: [PATCH 58/77] build: support Node.js 20.x in appveyor closes #5429 --- appveyor.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/appveyor.yml b/appveyor.yml index b865082930..cb3e835a89 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -21,6 +21,7 @@ environment: - nodejs_version: "17.9" - nodejs_version: "18.19" - nodejs_version: "19.9" + - nodejs_version: "20.11" cache: - node_modules install: From c259c3407f8c503c83d95fb1f30b132b73bb6388 Mon Sep 17 00:00:00 2001 From: Ulises Gascon Date: Fri, 2 Feb 2024 15:38:07 +0100 Subject: [PATCH 59/77] build: support Node.js 21.x --- .github/workflows/ci.yml | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index df123370d9..e880f74dab 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -33,6 +33,7 @@ jobs: - Node.js 18.x - Node.js 19.x - Node.js 20.x + - Node.js 21.x include: - name: Node.js 0.10 @@ -115,6 +116,10 @@ jobs: - name: Node.js 20.x node-version: "20.11" + + - name: Node.js 21.x + node-version: "21.6.1" + steps: - uses: actions/checkout@v4 From b9fea1224516e372f6f63480cc1830e5f6ee63e6 Mon Sep 17 00:00:00 2001 From: Ulises Gascon Date: Fri, 2 Feb 2024 16:31:54 +0100 Subject: [PATCH 60/77] build: support Node.js 21.x in appveyor --- appveyor.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/appveyor.yml b/appveyor.yml index cb3e835a89..5c01a8d02a 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -22,6 +22,7 @@ environment: - nodejs_version: "18.19" - nodejs_version: "19.9" - nodejs_version: "20.11" + - nodejs_version: "21.6.1" cache: - node_modules install: From 23b44b3ddd45bc68487cc34cd576b117ba9d2609 Mon Sep 17 00:00:00 2001 From: Ulises Gascon Date: Sat, 17 Feb 2024 18:23:09 +0100 Subject: [PATCH 61/77] build: support Node.js 21.6.2 --- .github/workflows/ci.yml | 2 +- appveyor.yml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index e880f74dab..aa231b74d2 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -118,7 +118,7 @@ jobs: node-version: "20.11" - name: Node.js 21.x - node-version: "21.6.1" + node-version: "21.6.2" steps: - uses: actions/checkout@v4 diff --git a/appveyor.yml b/appveyor.yml index 5c01a8d02a..8ece802a7f 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -22,7 +22,7 @@ environment: - nodejs_version: "18.19" - nodejs_version: "19.9" - nodejs_version: "20.11" - - nodejs_version: "21.6.1" + - nodejs_version: "21.6.2" cache: - node_modules install: From e3eca805847e0057ab1c83e7d61a6cc1c1ca47f1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ulises=20Gasc=C3=B3n?= Date: Tue, 20 Feb 2024 08:44:27 +0100 Subject: [PATCH 62/77] build: pin Node 21.x to minor Co-authored-by: Aravind Nair <22199259+aravindvnair99@users.noreply.github.com> --- appveyor.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/appveyor.yml b/appveyor.yml index 8ece802a7f..ce26523b3a 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -22,7 +22,7 @@ environment: - nodejs_version: "18.19" - nodejs_version: "19.9" - nodejs_version: "20.11" - - nodejs_version: "21.6.2" + - nodejs_version: "21.6" cache: - node_modules install: From b625132864ef40b1fb119ff7c7b984573a7974c6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ulises=20Gasc=C3=B3n?= Date: Tue, 20 Feb 2024 08:44:34 +0100 Subject: [PATCH 63/77] build: pin Node 21.x to minor Co-authored-by: Aravind Nair <22199259+aravindvnair99@users.noreply.github.com> closes #5430 --- .github/workflows/ci.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index aa231b74d2..01c82f8196 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -118,7 +118,7 @@ jobs: node-version: "20.11" - name: Node.js 21.x - node-version: "21.6.2" + node-version: "21.6" steps: - uses: actions/checkout@v4 From 1b51edac7c5f2844e23602164a52643bb625993a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ulises=20Gasc=C3=B3n?= Date: Mon, 26 Feb 2024 20:20:53 +0100 Subject: [PATCH 64/77] 4.18.3 --- History.md | 2 +- package.json | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/History.md b/History.md index 9e85df3ceb..0784045557 100644 --- a/History.md +++ b/History.md @@ -1,4 +1,4 @@ -unreleased +4.18.3 / 2024-02-26 ========== * Fix routing requests without method diff --git a/package.json b/package.json index cf36773643..c3845d2d4b 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "express", "description": "Fast, unopinionated, minimalist web framework", - "version": "4.18.2", + "version": "4.18.3", "author": "TJ Holowaychuk ", "contributors": [ "Aaron Heckmann ", From 06c6b88808f6d836afc58296812235a96d708b33 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ulises=20Gasc=C3=B3n?= Date: Sun, 10 Mar 2024 20:04:02 +0100 Subject: [PATCH 65/77] docs: update release date --- History.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/History.md b/History.md index 0784045557..b674cab4b0 100644 --- a/History.md +++ b/History.md @@ -1,4 +1,4 @@ -4.18.3 / 2024-02-26 +4.18.3 / 2024-02-29 ========== * Fix routing requests without method From 414854b82ea4312f50641ddf7668c9194c3c209c Mon Sep 17 00:00:00 2001 From: Wes Todd Date: Thu, 29 Feb 2024 08:49:34 -0600 Subject: [PATCH 66/77] docs: nominating @wesleytodd to be project captian --- Contributing.md | 22 ++++++++++++++++++---- 1 file changed, 18 insertions(+), 4 deletions(-) diff --git a/Contributing.md b/Contributing.md index dfe5f13833..7311454dd8 100644 --- a/Contributing.md +++ b/Contributing.md @@ -154,7 +154,21 @@ dissent. When the PR is merged, a TC member will add them to the proper GitHub/ ### Current Project Captains -- `expressjs.com`: @crandmck -- `multer`: @LinusU -- `path-to-regexp`: @blakeembrey -- `router`: @dougwilson +- `expressjs/express`: @wesleytodd +- `expressjs/discussions`: @wesleytodd +- `expressjs/expressjs.com`: @crandmck +- `expressjs/body-parser`: @wesleytodd +- `expressjs/multer`: @LinusU +- `expressjs/cookie-parser`: @wesleytodd +- `expressjs/generator`: @wesleytodd +- `expressjs/statusboard`: @wesleytodd +- `pillarjs/path-to-regexp`: @blakeembrey +- `pillarjs/router`: @dougwilson, @wesleytodd +- `pillarjs/finalhandler`: @wesleytodd +- `pillarjs/request`: @wesleytodd +- `jshttp/http-errors`: @wesleytodd +- `jshttp/cookie`: @wesleytodd +- `jshttp/on-finished`: @wesleytodd +- `jshttp/forwarded`: @wesleytodd +- `jshttp/proxy-addr`: @wesleytodd + From 4ee853e837dcc6c6c9f93c52278abe775c717fa1 Mon Sep 17 00:00:00 2001 From: Wes Todd Date: Wed, 28 Feb 2024 14:49:11 -0600 Subject: [PATCH 67/77] docs: loosen TC activity rules --- Contributing.md | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/Contributing.md b/Contributing.md index 7311454dd8..a9ba84690c 100644 --- a/Contributing.md +++ b/Contributing.md @@ -118,11 +118,13 @@ nominate someone to take their place. TC members will be added as admin's on the Github orgs, npm orgs, and other resources as necessary to be effective in the role. -To remain "active" a TC member should have participation within the last 6 months and miss -no more than three consecutive TC meetings. Members who do not meet this are expected to step down. -If A TC member does not step down, an issue can be opened in the discussions repo to move them -to inactive status. TC members who step down or are removed due to inactivity will be moved -into inactive status. +To remain "active" a TC member should have participation within the last 12 months and miss +no more than six consecutive TC meetings. Our goal is to increase participation, not punish +people for any lack of participation, this guideline should be only be used as such +(replace an inactive member with a new active one, for example). Members who do not meet this +are expected to step down. If A TC member does not step down, an issue can be opened in the +discussions repo to move them to inactive status. TC members who step down or are removed due +to inactivity will be moved into inactive status. Inactive status members can become active members by self nomination if the TC is not already larger than the maximum of 10. They will also be given preference if, while at max size, an From 69a4cf2819c4449ec6ea45649691fb43a528d5d1 Mon Sep 17 00:00:00 2001 From: Rich Hodgkins Date: Thu, 11 Jan 2024 11:36:11 +0000 Subject: [PATCH 68/77] deps: cookie@0.6.0 closes #5404 --- History.md | 7 +++++++ package.json | 2 +- test/res.cookie.js | 16 ++++++++++++++++ 3 files changed, 24 insertions(+), 1 deletion(-) diff --git a/History.md b/History.md index b674cab4b0..0559bb012c 100644 --- a/History.md +++ b/History.md @@ -1,3 +1,8 @@ +unreleased +========== + + * deps: cookie@0.6.0 + 4.18.3 / 2024-02-29 ========== @@ -6,6 +11,8 @@ - Fix strict json error message on Node.js 19+ - deps: content-type@~1.0.5 - deps: raw-body@2.5.2 + * deps: cookie@0.6.0 + - Add `partitioned` option 4.18.2 / 2022-10-08 =================== diff --git a/package.json b/package.json index c3845d2d4b..990e98dc1a 100644 --- a/package.json +++ b/package.json @@ -33,7 +33,7 @@ "body-parser": "1.20.2", "content-disposition": "0.5.4", "content-type": "~1.0.4", - "cookie": "0.5.0", + "cookie": "0.6.0", "cookie-signature": "1.0.6", "debug": "2.6.9", "depd": "2.0.0", diff --git a/test/res.cookie.js b/test/res.cookie.js index 93deb76988..c837820605 100644 --- a/test/res.cookie.js +++ b/test/res.cookie.js @@ -82,6 +82,22 @@ describe('res', function(){ }) }) + describe('partitioned', function () { + it('should set partitioned', function (done) { + var app = express(); + + app.use(function (req, res) { + res.cookie('name', 'tobi', { partitioned: true }); + res.end(); + }); + + request(app) + .get('/') + .expect('Set-Cookie', 'name=tobi; Path=/; Partitioned') + .expect(200, done) + }) + }) + describe('maxAge', function(){ it('should set relative expires', function(done){ var app = express(); From 567c9c665d0de4c344b8e160146050770233783c Mon Sep 17 00:00:00 2001 From: Rand McKinney Date: Sat, 16 Mar 2024 11:57:42 -0600 Subject: [PATCH 69/77] Add note on how to update docs for new release (#5541) * Update Release-Process.md Add note about updating docs. * Update Release-Process.md * Update Release-Process.md --- Release-Process.md | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/Release-Process.md b/Release-Process.md index ae740972f7..55e6218925 100644 --- a/Release-Process.md +++ b/Release-Process.md @@ -184,3 +184,9 @@ $ npm publish **NOTE:** The version number to publish will be picked up automatically from package.json. + +### Step 7. Update documentation website + +The documentation website https://expressjs.com/ documents the current release version in various places. For a new release: +1. Change the value of `current_version` in https://github.com/expressjs/expressjs.com/blob/gh-pages/_data/express.yml to match the latest version number. +2. Add a new section to the change log. For example, for a 4.x release, https://github.com/expressjs/expressjs.com/blob/gh-pages/en/changelog/4x.md, From 0867302ddbde0e9463d0564fea5861feb708c2dd Mon Sep 17 00:00:00 2001 From: FDrag0n <34733637+FDrag0n@users.noreply.github.com> Date: Fri, 15 Mar 2024 15:49:01 +0800 Subject: [PATCH 70/77] Prevent open redirect allow list bypass due to encodeurl Co-authored-by: Jon Church --- lib/response.js | 20 ++++++++++++++++++- test/res.location.js | 46 +++++++++++++++++++++++++++++++++++++++++++- 2 files changed, 64 insertions(+), 2 deletions(-) diff --git a/lib/response.js b/lib/response.js index fede486c06..f7c94d10e7 100644 --- a/lib/response.js +++ b/lib/response.js @@ -34,6 +34,7 @@ var extname = path.extname; var mime = send.mime; var resolve = path.resolve; var vary = require('vary'); +var urlParse = require('url').parse; /** * Response prototype. @@ -911,8 +912,25 @@ res.location = function location(url) { loc = this.req.get('Referrer') || '/'; } + var lowerLoc = loc.toLowerCase(); + var encodedUrl = encodeUrl(loc); + if (lowerLoc.indexOf('https://') === 0 || lowerLoc.indexOf('http://') === 0) { + try { + var parsedUrl = urlParse(loc); + var parsedEncodedUrl = urlParse(encodedUrl); + // Because this can encode the host, check that we did not change the host + if (parsedUrl.host !== parsedEncodedUrl.host) { + // If the host changes after encodeUrl, return the original url + return this.set('Location', loc); + } + } catch (e) { + // If parse fails, return the original url + return this.set('Location', loc); + } + } + // set location - return this.set('Location', encodeUrl(loc)); + return this.set('Location', encodedUrl); }; /** diff --git a/test/res.location.js b/test/res.location.js index 158afac01e..38cab027a8 100644 --- a/test/res.location.js +++ b/test/res.location.js @@ -1,13 +1,27 @@ 'use strict' var express = require('../') - , request = require('supertest'); + , request = require('supertest') + , url = require('url'); describe('res', function(){ describe('.location(url)', function(){ it('should set the header', function(done){ var app = express(); + app.use(function(req, res){ + res.location('http://google.com/').end(); + }); + + request(app) + .get('/') + .expect('Location', 'http://google.com/') + .expect(200, done) + }) + + it('should preserve trailing slashes when not present', function(done){ + var app = express(); + app.use(function(req, res){ res.location('http://google.com').end(); }); @@ -31,6 +45,36 @@ describe('res', function(){ .expect(200, done) }) + it('should not encode bad "url"', function (done) { + var app = express() + + app.use(function (req, res) { + // This is here to show a basic check one might do which + // would pass but then the location header would still be bad + if (url.parse(req.query.q).host !== 'google.com') { + res.status(400).end('Bad url'); + } + res.location(req.query.q).end(); + }); + + request(app) + .get('/?q=http://google.com\\@apple.com') + .expect(200) + .expect('Location', 'http://google.com\\@apple.com') + .end(function (err) { + if (err) { + throw err; + } + + // This ensures that our protocol check is case insensitive + request(app) + .get('/?q=HTTP://google.com\\@apple.com') + .expect(200) + .expect('Location', 'HTTP://google.com\\@apple.com') + .end(done) + }); + }); + it('should not touch already-encoded sequences in "url"', function (done) { var app = express() From 084e36506a18774f85206a65d8da04dc1107fc1b Mon Sep 17 00:00:00 2001 From: Wes Todd Date: Wed, 20 Mar 2024 10:09:10 -0500 Subject: [PATCH 71/77] 4.19.0 --- History.md | 3 ++- package.json | 2 +- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/History.md b/History.md index 0559bb012c..877f1c56fb 100644 --- a/History.md +++ b/History.md @@ -1,6 +1,7 @@ -unreleased +4.18.3 / 2024-03-20 ========== + * Prevent open redirect allow list bypass due to encodeurl * deps: cookie@0.6.0 4.18.3 / 2024-02-29 diff --git a/package.json b/package.json index 990e98dc1a..eca07b57c8 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "express", "description": "Fast, unopinionated, minimalist web framework", - "version": "4.18.3", + "version": "4.19.0", "author": "TJ Holowaychuk ", "contributors": [ "Aaron Heckmann ", From 11f2b1db227fd42c2508c427032c1ec671b306be Mon Sep 17 00:00:00 2001 From: Wes Todd Date: Wed, 20 Mar 2024 11:33:31 -0500 Subject: [PATCH 72/77] build: fix build due to inconsistent supertest behavior in older versions --- test/res.location.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/test/res.location.js b/test/res.location.js index 38cab027a8..71fbaec03d 100644 --- a/test/res.location.js +++ b/test/res.location.js @@ -58,7 +58,7 @@ describe('res', function(){ }); request(app) - .get('/?q=http://google.com\\@apple.com') + .get('/?q=http://google.com' + encodeURIComponent('\\@apple.com')) .expect(200) .expect('Location', 'http://google.com\\@apple.com') .end(function (err) { @@ -68,7 +68,7 @@ describe('res', function(){ // This ensures that our protocol check is case insensitive request(app) - .get('/?q=HTTP://google.com\\@apple.com') + .get('/?q=HTTP://google.com' + encodeURIComponent('\\@apple.com')) .expect(200) .expect('Location', 'HTTP://google.com\\@apple.com') .end(done) From a1fa90fcea7d8e844e1c9938ad095d62669c3abd Mon Sep 17 00:00:00 2001 From: Wes Todd Date: Wed, 20 Mar 2024 16:39:46 -0500 Subject: [PATCH 73/77] fixed un-edited version in history.md for 4.19.0 --- History.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/History.md b/History.md index 877f1c56fb..b6208ea7e3 100644 --- a/History.md +++ b/History.md @@ -1,4 +1,4 @@ -4.18.3 / 2024-03-20 +4.19.0 / 2024-03-20 ========== * Prevent open redirect allow list bypass due to encodeurl From a003cfab034fbadb1c78ae337ee8ab389adda217 Mon Sep 17 00:00:00 2001 From: Wes Todd Date: Wed, 20 Mar 2024 16:39:46 -0500 Subject: [PATCH 74/77] Allow passing non-strings to res.location with new encoding handling checks fixes #5554 #5555 --- History.md | 5 +++++ lib/response.js | 2 +- test/res.location.js | 15 +++++++++++++++ 3 files changed, 21 insertions(+), 1 deletion(-) diff --git a/History.md b/History.md index b6208ea7e3..2fda95c155 100644 --- a/History.md +++ b/History.md @@ -1,3 +1,8 @@ +unreleased changes +========== + + * Allow passing non-strings to res.location with new encoding handling checks + 4.19.0 / 2024-03-20 ========== diff --git a/lib/response.js b/lib/response.js index f7c94d10e7..6fddbf3516 100644 --- a/lib/response.js +++ b/lib/response.js @@ -905,7 +905,7 @@ res.cookie = function (name, value, options) { */ res.location = function location(url) { - var loc = url; + var loc = String(url); // "back" is an alias for the referrer if (url === 'back') { diff --git a/test/res.location.js b/test/res.location.js index 71fbaec03d..d1bbf4b687 100644 --- a/test/res.location.js +++ b/test/res.location.js @@ -145,5 +145,20 @@ describe('res', function(){ .expect(200, done) }) }) + + if (typeof URL !== 'undefined') { + it('should accept an instance of URL', function (done) { + var app = express(); + + app.use(function(req, res){ + res.location(new URL('http://google.com/')).end(); + }); + + request(app) + .get('/') + .expect('Location', 'http://google.com/') + .expect(200, done); + }); + } }) }) From 4f0f6cc67d531431c096ea006c2191b92931bbc3 Mon Sep 17 00:00:00 2001 From: Wes Todd Date: Wed, 20 Mar 2024 17:17:59 -0500 Subject: [PATCH 75/77] 4.19.1 --- History.md | 2 +- package.json | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/History.md b/History.md index 2fda95c155..c4cdd94dac 100644 --- a/History.md +++ b/History.md @@ -1,4 +1,4 @@ -unreleased changes +4.19.1 / 2024-03-20 ========== * Allow passing non-strings to res.location with new encoding handling checks diff --git a/package.json b/package.json index eca07b57c8..51c6aba212 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "express", "description": "Fast, unopinionated, minimalist web framework", - "version": "4.19.0", + "version": "4.19.1", "author": "TJ Holowaychuk ", "contributors": [ "Aaron Heckmann ", From da4d763ff6ba9df6dbd8f1f0b1d05412dda934d5 Mon Sep 17 00:00:00 2001 From: Wes Todd Date: Thu, 21 Mar 2024 12:13:56 -0500 Subject: [PATCH 76/77] Improved fix for open redirect allow list bypass Co-authored-by: Jon Church Co-authored-by: Blake Embrey --- History.md | 5 + lib/response.js | 31 ++--- test/res.location.js | 307 +++++++++++++++++++++++++++++++++++++------ 3 files changed, 280 insertions(+), 63 deletions(-) diff --git a/History.md b/History.md index c4cdd94dac..f62574a7ee 100644 --- a/History.md +++ b/History.md @@ -1,3 +1,8 @@ +unreleased +========== + + * Improved fix for open redirect allow list bypass + 4.19.1 / 2024-03-20 ========== diff --git a/lib/response.js b/lib/response.js index 6fddbf3516..dd7b3c8201 100644 --- a/lib/response.js +++ b/lib/response.js @@ -34,7 +34,6 @@ var extname = path.extname; var mime = send.mime; var resolve = path.resolve; var vary = require('vary'); -var urlParse = require('url').parse; /** * Response prototype. @@ -56,6 +55,7 @@ module.exports = res */ var charsetRegExp = /;\s*charset\s*=/; +var schemaAndHostRegExp = /^(?:[a-zA-Z][a-zA-Z0-9+.-]*:)?\/\/[^\\\/\?]+/; /** * Set status `code`. @@ -905,32 +905,23 @@ res.cookie = function (name, value, options) { */ res.location = function location(url) { - var loc = String(url); + var loc; // "back" is an alias for the referrer if (url === 'back') { loc = this.req.get('Referrer') || '/'; + } else { + loc = String(url); } - var lowerLoc = loc.toLowerCase(); - var encodedUrl = encodeUrl(loc); - if (lowerLoc.indexOf('https://') === 0 || lowerLoc.indexOf('http://') === 0) { - try { - var parsedUrl = urlParse(loc); - var parsedEncodedUrl = urlParse(encodedUrl); - // Because this can encode the host, check that we did not change the host - if (parsedUrl.host !== parsedEncodedUrl.host) { - // If the host changes after encodeUrl, return the original url - return this.set('Location', loc); - } - } catch (e) { - // If parse fails, return the original url - return this.set('Location', loc); - } - } + var m = schemaAndHostRegExp.exec(loc); + var pos = m ? m[0].length + 1 : 0; + + // Only encode after host to avoid invalid encoding which can introduce + // vulnerabilities (e.g. `\\` to `%5C`). + loc = loc.slice(0, pos) + encodeUrl(loc.slice(pos)); - // set location - return this.set('Location', encodedUrl); + return this.set('Location', loc); }; /** diff --git a/test/res.location.js b/test/res.location.js index d1bbf4b687..c80b38de6b 100644 --- a/test/res.location.js +++ b/test/res.location.js @@ -2,6 +2,7 @@ var express = require('../') , request = require('supertest') + , assert = require('assert') , url = require('url'); describe('res', function(){ @@ -45,49 +46,6 @@ describe('res', function(){ .expect(200, done) }) - it('should not encode bad "url"', function (done) { - var app = express() - - app.use(function (req, res) { - // This is here to show a basic check one might do which - // would pass but then the location header would still be bad - if (url.parse(req.query.q).host !== 'google.com') { - res.status(400).end('Bad url'); - } - res.location(req.query.q).end(); - }); - - request(app) - .get('/?q=http://google.com' + encodeURIComponent('\\@apple.com')) - .expect(200) - .expect('Location', 'http://google.com\\@apple.com') - .end(function (err) { - if (err) { - throw err; - } - - // This ensures that our protocol check is case insensitive - request(app) - .get('/?q=HTTP://google.com' + encodeURIComponent('\\@apple.com')) - .expect(200) - .expect('Location', 'HTTP://google.com\\@apple.com') - .end(done) - }); - }); - - it('should not touch already-encoded sequences in "url"', function (done) { - var app = express() - - app.use(function (req, res) { - res.location('https://google.com?q=%A710').end() - }) - - request(app) - .get('/') - .expect('Location', 'https://google.com?q=%A710') - .expect(200, done) - }) - describe('when url is "back"', function () { it('should set location from "Referer" header', function (done) { var app = express() @@ -146,6 +104,79 @@ describe('res', function(){ }) }) + it('should encode data uri', function (done) { + var app = express() + app.use(function (req, res) { + res.location('data:text/javascript,export default () => { }').end(); + }); + + request(app) + .get('/') + .expect('Location', 'data:text/javascript,export%20default%20()%20=%3E%20%7B%20%7D') + .expect(200, done) + }) + + it('should encode data uri', function (done) { + var app = express() + app.use(function (req, res) { + res.location('data:text/javascript,export default () => { }').end(); + }); + + request(app) + .get('/') + .expect('Location', 'data:text/javascript,export%20default%20()%20=%3E%20%7B%20%7D') + .expect(200, done) + }) + + it('should consistently handle non-string input: boolean', function (done) { + var app = express() + app.use(function (req, res) { + res.location(true).end(); + }); + + request(app) + .get('/') + .expect('Location', 'true') + .expect(200, done) + }); + + it('should consistently handle non-string inputs: object', function (done) { + var app = express() + app.use(function (req, res) { + res.location({}).end(); + }); + + request(app) + .get('/') + .expect('Location', '[object%20Object]') + .expect(200, done) + }); + + it('should consistently handle non-string inputs: array', function (done) { + var app = express() + app.use(function (req, res) { + res.location([]).end(); + }); + + request(app) + .get('/') + .expect('Location', '') + .expect(200, done) + }); + + it('should consistently handle empty string input', function (done) { + var app = express() + app.use(function (req, res) { + res.location('').end(); + }); + + request(app) + .get('/') + .expect('Location', '') + .expect(200, done) + }); + + if (typeof URL !== 'undefined') { it('should accept an instance of URL', function (done) { var app = express(); @@ -161,4 +192,194 @@ describe('res', function(){ }); } }) + + describe('location header encoding', function() { + function createRedirectServerForDomain (domain) { + var app = express(); + app.use(function (req, res) { + var host = url.parse(req.query.q, false, true).host; + // This is here to show a basic check one might do which + // would pass but then the location header would still be bad + if (host !== domain) { + res.status(400).end('Bad host: ' + host + ' !== ' + domain); + } + res.location(req.query.q).end(); + }); + return app; + } + + function testRequestedRedirect (app, inputUrl, expected, expectedHost, done) { + return request(app) + // Encode uri because old supertest does not and is required + // to test older node versions. New supertest doesn't re-encode + // so this works in both. + .get('/?q=' + encodeURIComponent(inputUrl)) + .expect('') // No body. + .expect(200) + .expect('Location', expected) + .end(function (err, res) { + if (err) { + console.log('headers:', res.headers) + console.error('error', res.error, err); + return done(err, res); + } + + // Parse the hosts from the input URL and the Location header + var inputHost = url.parse(inputUrl, false, true).host; + var locationHost = url.parse(res.headers['location'], false, true).host; + + assert.strictEqual(locationHost, expectedHost); + + // Assert that the hosts are the same + if (inputHost !== locationHost) { + return done(new Error('Hosts do not match: ' + inputHost + " !== " + locationHost)); + } + + return done(null, res); + }); + } + + it('should not touch already-encoded sequences in "url"', function (done) { + var app = createRedirectServerForDomain('google.com'); + testRequestedRedirect( + app, + 'https://google.com?q=%A710', + 'https://google.com?q=%A710', + 'google.com', + done + ); + }); + + it('should consistently handle relative urls', function (done) { + var app = createRedirectServerForDomain(null); + testRequestedRedirect( + app, + '/foo/bar', + '/foo/bar', + null, + done + ); + }); + + it('should not encode urls in such a way that they can bypass redirect allow lists', function (done) { + var app = createRedirectServerForDomain('google.com'); + testRequestedRedirect( + app, + 'http://google.com\\@apple.com', + 'http://google.com\\@apple.com', + 'google.com', + done + ); + }); + + it('should not be case sensitive', function (done) { + var app = createRedirectServerForDomain('google.com'); + testRequestedRedirect( + app, + 'HTTP://google.com\\@apple.com', + 'HTTP://google.com\\@apple.com', + 'google.com', + done + ); + }); + + it('should work with https', function (done) { + var app = createRedirectServerForDomain('google.com'); + testRequestedRedirect( + app, + 'https://google.com\\@apple.com', + 'https://google.com\\@apple.com', + 'google.com', + done + ); + }); + + it('should correctly encode schemaless paths', function (done) { + var app = createRedirectServerForDomain('google.com'); + testRequestedRedirect( + app, + '//google.com\\@apple.com/', + '//google.com\\@apple.com/', + 'google.com', + done + ); + }); + + it('should percent encode backslashes in the path', function (done) { + var app = createRedirectServerForDomain('google.com'); + testRequestedRedirect( + app, + 'https://google.com/foo\\bar\\baz', + 'https://google.com/foo%5Cbar%5Cbaz', + 'google.com', + done + ); + }); + + it('should encode backslashes in the path after the first backslash that triggered path parsing', function (done) { + var app = createRedirectServerForDomain('google.com'); + testRequestedRedirect( + app, + 'https://google.com\\@app\\l\\e.com', + 'https://google.com\\@app%5Cl%5Ce.com', + 'google.com', + done + ); + }); + + it('should escape header splitting for old node versions', function (done) { + var app = createRedirectServerForDomain('google.com'); + testRequestedRedirect( + app, + 'http://google.com\\@apple.com/%0d%0afoo:%20bar', + 'http://google.com\\@apple.com/%0d%0afoo:%20bar', + 'google.com', + done + ); + }); + + it('should encode unicode correctly', function (done) { + var app = createRedirectServerForDomain(null); + testRequestedRedirect( + app, + '/%e2%98%83', + '/%e2%98%83', + null, + done + ); + }); + + it('should encode unicode correctly even with a bad host', function (done) { + var app = createRedirectServerForDomain('google.com'); + testRequestedRedirect( + app, + 'http://google.com\\@apple.com/%e2%98%83', + 'http://google.com\\@apple.com/%e2%98%83', + 'google.com', + done + ); + }); + + it('should work correctly despite using deprecated url.parse', function (done) { + var app = createRedirectServerForDomain('google.com'); + testRequestedRedirect( + app, + 'https://google.com\'.bb.com/1.html', + 'https://google.com\'.bb.com/1.html', + 'google.com', + done + ); + }); + + it('should encode file uri path', function (done) { + var app = createRedirectServerForDomain(''); + testRequestedRedirect( + app, + 'file:///etc\\passwd', + 'file:///etc%5Cpasswd', + '', + done + ); + }); + }); }) From 04bc62787be974874bc1467b23606c36bc9779ba Mon Sep 17 00:00:00 2001 From: Wes Todd Date: Mon, 25 Mar 2024 09:26:03 -0500 Subject: [PATCH 77/77] 4.19.2 --- History.md | 2 +- package.json | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/History.md b/History.md index f62574a7ee..ac2e7cf719 100644 --- a/History.md +++ b/History.md @@ -1,4 +1,4 @@ -unreleased +4.19.2 / 2024-03-25 ========== * Improved fix for open redirect allow list bypass diff --git a/package.json b/package.json index 51c6aba212..f299d882b0 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "express", "description": "Fast, unopinionated, minimalist web framework", - "version": "4.19.1", + "version": "4.19.2", "author": "TJ Holowaychuk ", "contributors": [ "Aaron Heckmann ",