From 02c753583eddabae2691b09a7babd747d449ca5f Mon Sep 17 00:00:00 2001 From: Douglas Christopher Wilson Date: Wed, 6 Jun 2018 23:50:03 -0400 Subject: [PATCH 001/270] build: Node.js@4.9 --- .travis.yml | 2 +- appveyor.yml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.travis.yml b/.travis.yml index edde93bcf0f..af0c01ad535 100644 --- a/.travis.yml +++ b/.travis.yml @@ -5,7 +5,7 @@ node_js: - "1.8" - "2.5" - "3.3" - - "4.8" + - "4.9" - "5.12" - "6.12" - "7.10" diff --git a/appveyor.yml b/appveyor.yml index ab65453be3b..5deb61cea33 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -5,7 +5,7 @@ environment: - nodejs_version: "1.8" - nodejs_version: "2.5" - nodejs_version: "3.3" - - nodejs_version: "4.8" + - nodejs_version: "4.9" - nodejs_version: "5.12" - nodejs_version: "6.12" - nodejs_version: "7.10" From 3d8ca8ad4aa0ad03ce2e4b27f6773d47e4fea201 Mon Sep 17 00:00:00 2001 From: Douglas Christopher Wilson Date: Thu, 7 Jun 2018 00:04:28 -0400 Subject: [PATCH 002/270] build: Node.js@6.14 --- .travis.yml | 2 +- appveyor.yml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.travis.yml b/.travis.yml index af0c01ad535..5c85496d1da 100644 --- a/.travis.yml +++ b/.travis.yml @@ -7,7 +7,7 @@ node_js: - "3.3" - "4.9" - "5.12" - - "6.12" + - "6.14" - "7.10" - "8.9" matrix: diff --git a/appveyor.yml b/appveyor.yml index 5deb61cea33..5c8161fa75a 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -7,7 +7,7 @@ environment: - nodejs_version: "3.3" - nodejs_version: "4.9" - nodejs_version: "5.12" - - nodejs_version: "6.12" + - nodejs_version: "6.14" - nodejs_version: "7.10" - nodejs_version: "8.9" cache: From ac89f6f121cbd17c957e8e493615c33e7f0f2687 Mon Sep 17 00:00:00 2001 From: Douglas Christopher Wilson Date: Thu, 7 Jun 2018 00:12:07 -0400 Subject: [PATCH 003/270] build: Node.js@8.11 --- .travis.yml | 2 +- appveyor.yml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.travis.yml b/.travis.yml index 5c85496d1da..acfb87c2065 100644 --- a/.travis.yml +++ b/.travis.yml @@ -9,7 +9,7 @@ node_js: - "5.12" - "6.14" - "7.10" - - "8.9" + - "8.11" matrix: include: - node_js: "9" diff --git a/appveyor.yml b/appveyor.yml index 5c8161fa75a..e5e653abe67 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -9,7 +9,7 @@ environment: - nodejs_version: "5.12" - nodejs_version: "6.14" - nodejs_version: "7.10" - - nodejs_version: "8.9" + - nodejs_version: "8.11" cache: - node_modules install: From f95dbc28fdb483dbd45b436386cf0db77322eb43 Mon Sep 17 00:00:00 2001 From: Douglas Christopher Wilson Date: Tue, 31 Jul 2018 17:09:27 -0400 Subject: [PATCH 004/270] build: should@13.2.3 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 7aa0f95b3ac..cf38858b5c1 100644 --- a/package.json +++ b/package.json @@ -73,7 +73,7 @@ "morgan": "1.9.0", "multiparty": "4.1.3", "pbkdf2-password": "1.2.1", - "should": "13.2.1", + "should": "13.2.3", "supertest": "1.2.0", "connect-redis": "~2.4.1", "vhost": "~3.0.2" From c39d7d933968b3cc03c6bf473920b8d5f24f7f43 Mon Sep 17 00:00:00 2001 From: Douglas Christopher Wilson Date: Thu, 13 Sep 2018 12:23:38 -0400 Subject: [PATCH 005/270] build: Node.js@8.12 --- .travis.yml | 2 +- appveyor.yml | 6 ++++-- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/.travis.yml b/.travis.yml index acfb87c2065..239e8071d12 100644 --- a/.travis.yml +++ b/.travis.yml @@ -9,7 +9,7 @@ node_js: - "5.12" - "6.14" - "7.10" - - "8.11" + - "8.12" matrix: include: - node_js: "9" diff --git a/appveyor.yml b/appveyor.yml index e5e653abe67..6e77e88bcdd 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -9,11 +9,13 @@ environment: - nodejs_version: "5.12" - nodejs_version: "6.14" - nodejs_version: "7.10" - - nodejs_version: "8.11" + - nodejs_version: "8.12" cache: - node_modules install: - - ps: Install-Product node $env:nodejs_version + - ps: >- + try { Install-Product node $env:nodejs_version -ErrorAction Stop } + catch { Update-NodeJsInstallation (Get-NodeJsLatestBuild $env:nodejs_version) } - npm config set shrinkwrap false - npm rm --save-dev connect-redis - if exist node_modules npm prune From d5b33cfad8efedc42ec36cab2ced75c2cfd99dce Mon Sep 17 00:00:00 2001 From: Douglas Christopher Wilson Date: Thu, 13 Sep 2018 12:26:36 -0400 Subject: [PATCH 006/270] build: update example dependencies --- package.json | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/package.json b/package.json index cf38858b5c1..0b87ae7657d 100644 --- a/package.json +++ b/package.json @@ -62,16 +62,16 @@ "after": "0.8.2", "cookie-parser": "~1.4.3", "cookie-session": "1.3.2", - "ejs": "2.5.7", + "ejs": "2.6.1", "eslint": "2.13.1", "express-session": "1.15.6", "hbs": "4.0.1", "istanbul": "0.4.5", - "marked": "0.3.17", - "method-override": "2.3.10", + "marked": "0.5.0", + "method-override": "3.0.0", "mocha": "3.5.3", - "morgan": "1.9.0", - "multiparty": "4.1.3", + "morgan": "1.9.1", + "multiparty": "4.2.1", "pbkdf2-password": "1.2.1", "should": "13.2.3", "supertest": "1.2.0", From ede24da9645ed771ddeb9cf327d042d35a31d42d Mon Sep 17 00:00:00 2001 From: Logan Ripplinger Date: Tue, 14 Aug 2018 18:41:14 -0700 Subject: [PATCH 007/270] examples: fix typo in multi-router example closes #3718 --- examples/multi-router/index.js | 2 +- test/acceptance/multi-router.js | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/examples/multi-router/index.js b/examples/multi-router/index.js index ff31e514a56..78bae9d6e36 100644 --- a/examples/multi-router/index.js +++ b/examples/multi-router/index.js @@ -6,7 +6,7 @@ app.use('/api/v1', require('./controllers/api_v1')); app.use('/api/v2', require('./controllers/api_v2')); app.get('/', function(req, res) { - res.send('Hello form root route.'); + res.send('Hello from root route.') }); /* istanbul ignore next */ diff --git a/test/acceptance/multi-router.js b/test/acceptance/multi-router.js index 9590ee94d41..4362a8300be 100644 --- a/test/acceptance/multi-router.js +++ b/test/acceptance/multi-router.js @@ -6,7 +6,7 @@ describe('multi-router', function(){ it('should respond with root handler', function(done){ request(app) .get('/') - .expect(200, 'Hello form root route.', done) + .expect(200, 'Hello from root route.', done) }) }) From f3fa758af9664526ee18c58764590e48f559e6ae Mon Sep 17 00:00:00 2001 From: Andreas Kohn Date: Sat, 26 May 2018 21:58:15 +0200 Subject: [PATCH 008/270] Fix JSDoc for Router constructor fixes #3598 fixes #3599 fixes #3698 --- History.md | 5 +++++ lib/router/index.js | 2 +- 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/History.md b/History.md index e02fcd5bf9e..9295b05feb6 100644 --- a/History.md +++ b/History.md @@ -1,3 +1,8 @@ +unreleased +========== + + * Fix JSDoc for `Router` constructor + 4.16.3 / 2018-03-12 =================== diff --git a/lib/router/index.js b/lib/router/index.js index 60727ed6d64..69e6d3800af 100644 --- a/lib/router/index.js +++ b/lib/router/index.js @@ -35,7 +35,7 @@ var toString = Object.prototype.toString; /** * Initialize a new `Router` with the given `options`. * - * @param {Object} options + * @param {Object} [options] * @return {Router} which is an callable function * @public */ From 431f65305eb78eba337356ec7637e4ee13d84195 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Linus=20Unneb=C3=A4ck?= Date: Wed, 27 Jun 2018 10:40:56 +0200 Subject: [PATCH 009/270] lint: move removed middlewares list to a variable closes #3558 closes #3677 closes #3678 --- lib/express.js | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/lib/express.js b/lib/express.js index 485a8fc08de..594007b5b43 100644 --- a/lib/express.js +++ b/lib/express.js @@ -84,7 +84,7 @@ exports.urlencoded = bodyParser.urlencoded * Replace removed middleware with an appropriate error message. */ -;[ +var removedMiddlewares = [ 'bodyParser', 'compress', 'cookieSession', @@ -101,8 +101,10 @@ exports.urlencoded = bodyParser.urlencoded 'directory', 'limit', 'multipart', - 'staticCache', -].forEach(function (name) { + 'staticCache' +] + +removedMiddlewares.forEach(function (name) { Object.defineProperty(exports, name, { get: function () { throw new Error('Most middleware (like ' + name + ') is no longer bundled with Express and must be installed separately. Please see https://github.com/senchalabs/connect#middleware.'); From b4eb1f59d39d801d7365c86b04500f16faeb0b1c Mon Sep 17 00:00:00 2001 From: Douglas Christopher Wilson Date: Tue, 18 Sep 2018 21:56:31 -0400 Subject: [PATCH 010/270] deps: qs@6.5.2 --- History.md | 1 + package.json | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/History.md b/History.md index 9295b05feb6..eda6c4d76f3 100644 --- a/History.md +++ b/History.md @@ -2,6 +2,7 @@ unreleased ========== * Fix JSDoc for `Router` constructor + * deps: qs@6.5.2 4.16.3 / 2018-03-12 =================== diff --git a/package.json b/package.json index 0b87ae7657d..1e10d5534ec 100644 --- a/package.json +++ b/package.json @@ -47,7 +47,7 @@ "parseurl": "~1.3.2", "path-to-regexp": "0.1.7", "proxy-addr": "~2.0.3", - "qs": "6.5.1", + "qs": "6.5.2", "range-parser": "~1.2.0", "safe-buffer": "5.1.1", "send": "0.16.2", From b8fb6a7fb1af155b1259d25418dc807112e02138 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Felix=20Bu=CC=88nemann?= Date: Tue, 15 May 2018 23:45:17 +0200 Subject: [PATCH 011/270] deps: body-parser@1.18.3 closes #3655 closes #3706 --- History.md | 9 +++++++++ package.json | 2 +- 2 files changed, 10 insertions(+), 1 deletion(-) diff --git a/History.md b/History.md index eda6c4d76f3..bc77d81ed9e 100644 --- a/History.md +++ b/History.md @@ -2,6 +2,15 @@ unreleased ========== * Fix JSDoc for `Router` constructor + * deps: body-parser@1.18.3 + - Fix deprecation warnings on Node.js 10+ + - Fix stack trace for strict json parse error + - deps: depd@~1.1.2 + - deps: http-errors@~1.6.3 + - deps: iconv-lite@0.4.23 + - deps: qs@6.5.2 + - deps: raw-body@2.3.3 + - deps: type-is@~1.6.16 * deps: qs@6.5.2 4.16.3 / 2018-03-12 diff --git a/package.json b/package.json index 1e10d5534ec..3b6eac1187b 100644 --- a/package.json +++ b/package.json @@ -29,7 +29,7 @@ "dependencies": { "accepts": "~1.3.5", "array-flatten": "1.1.1", - "body-parser": "1.18.2", + "body-parser": "1.18.3", "content-disposition": "0.5.2", "content-type": "~1.0.4", "cookie": "0.3.1", From 4480fb997e9132a8b1e8b23d1a2766d27a918909 Mon Sep 17 00:00:00 2001 From: Douglas Christopher Wilson Date: Wed, 19 Sep 2018 12:40:40 -0400 Subject: [PATCH 012/270] deps: proxy-addr@~2.0.4 --- History.md | 2 ++ package.json | 2 +- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/History.md b/History.md index bc77d81ed9e..d7b08c54484 100644 --- a/History.md +++ b/History.md @@ -11,6 +11,8 @@ unreleased - deps: qs@6.5.2 - deps: raw-body@2.3.3 - deps: type-is@~1.6.16 + * deps: proxy-addr@~2.0.4 + - deps: ipaddr.js@1.8.0 * deps: qs@6.5.2 4.16.3 / 2018-03-12 diff --git a/package.json b/package.json index 3b6eac1187b..a0da2a7320a 100644 --- a/package.json +++ b/package.json @@ -46,7 +46,7 @@ "on-finished": "~2.3.0", "parseurl": "~1.3.2", "path-to-regexp": "0.1.7", - "proxy-addr": "~2.0.3", + "proxy-addr": "~2.0.4", "qs": "6.5.2", "range-parser": "~1.2.0", "safe-buffer": "5.1.1", From 5de1a08ebff4c33d0c452510217193905f34cbe9 Mon Sep 17 00:00:00 2001 From: Douglas Christopher Wilson Date: Wed, 19 Sep 2018 14:06:22 -0400 Subject: [PATCH 013/270] build: supertest@2.0.0 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index a0da2a7320a..8bc9069a8fc 100644 --- a/package.json +++ b/package.json @@ -74,7 +74,7 @@ "multiparty": "4.2.1", "pbkdf2-password": "1.2.1", "should": "13.2.3", - "supertest": "1.2.0", + "supertest": "2.0.0", "connect-redis": "~2.4.1", "vhost": "~3.0.2" }, From 5e9de5dcb6f1ff396038ded11951aa53c62a07a4 Mon Sep 17 00:00:00 2001 From: Douglas Christopher Wilson Date: Wed, 19 Sep 2018 14:47:48 -0400 Subject: [PATCH 014/270] deps: safe-buffer@5.1.2 --- History.md | 1 + package.json | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/History.md b/History.md index d7b08c54484..ef1733fc26e 100644 --- a/History.md +++ b/History.md @@ -14,6 +14,7 @@ unreleased * deps: proxy-addr@~2.0.4 - deps: ipaddr.js@1.8.0 * deps: qs@6.5.2 + * deps: safe-buffer@5.1.2 4.16.3 / 2018-03-12 =================== diff --git a/package.json b/package.json index 8bc9069a8fc..45faac1c6ba 100644 --- a/package.json +++ b/package.json @@ -49,7 +49,7 @@ "proxy-addr": "~2.0.4", "qs": "6.5.2", "range-parser": "~1.2.0", - "safe-buffer": "5.1.1", + "safe-buffer": "5.1.2", "send": "0.16.2", "serve-static": "1.13.2", "setprototypeof": "1.1.0", From 3d10279826f59bf68e28995ce423f7bc4d2f11cf Mon Sep 17 00:00:00 2001 From: Douglas Christopher Wilson Date: Wed, 19 Sep 2018 23:25:16 -0400 Subject: [PATCH 015/270] Fix issue where "Request aborted" may be logged in res.sendfile --- History.md | 1 + lib/response.js | 2 +- test/res.sendFile.js | 26 +++++++++++++++++--------- 3 files changed, 19 insertions(+), 10 deletions(-) diff --git a/History.md b/History.md index ef1733fc26e..2d902e94d61 100644 --- a/History.md +++ b/History.md @@ -1,6 +1,7 @@ unreleased ========== + * Fix issue where `"Request aborted"` may be logged in `res.sendfile` * Fix JSDoc for `Router` constructor * deps: body-parser@1.18.3 - Fix deprecation warnings on Node.js 10+ diff --git a/lib/response.js b/lib/response.js index 9c1796d37b3..2e445ac02c5 100644 --- a/lib/response.js +++ b/lib/response.js @@ -500,7 +500,7 @@ res.sendfile = function (path, options, callback) { if (err && err.code === 'EISDIR') return next(); // next() all but write errors - if (err && err.code !== 'ECONNABORT' && err.syscall !== 'write') { + if (err && err.code !== 'ECONNABORTED' && err.syscall !== 'write') { next(err); } }); diff --git a/test/res.sendFile.js b/test/res.sendFile.js index ccec3f40cfe..46cf98bd3b9 100644 --- a/test/res.sendFile.js +++ b/test/res.sendFile.js @@ -96,25 +96,29 @@ describe('res', function(){ }) it('should not error if the client aborts', function (done) { - var cb = after(1, done); var app = express(); + var cb = after(2, done) + var error = null app.use(function (req, res) { setImmediate(function () { res.sendFile(path.resolve(fixtures, 'name.txt')); server.close(cb) - }); + setTimeout(function () { + cb(error) + }, 10) + }) test.abort(); }); app.use(function (err, req, res, next) { - err.code.should.be.empty() - cb(); + error = err + next(err) }); var server = app.listen() var test = request(server).get('/') - test.expect(200, cb); + test.end() }) describe('with "cacheControl" option', function () { @@ -628,25 +632,29 @@ describe('res', function(){ }); it('should not error if the client aborts', function (done) { - var cb = after(1, done); var app = express(); + var cb = after(2, done) + var error = null app.use(function (req, res) { setImmediate(function () { res.sendfile(path.resolve(fixtures, 'name.txt')); server.close(cb) + setTimeout(function () { + cb(error) + }, 10) }); test.abort(); }); app.use(function (err, req, res, next) { - err.code.should.be.empty() - cb(); + error = err + next(err) }); var server = app.listen() var test = request(server).get('/') - test.expect(200, cb); + test.end() }) describe('with an absolute path', function(){ From 09d5654488f707db2ee05e0358bb74caa44fed91 Mon Sep 17 00:00:00 2001 From: Douglas Christopher Wilson Date: Fri, 21 Sep 2018 23:01:22 -0400 Subject: [PATCH 016/270] build: restructure CI build steps --- .travis.yml | 32 ++++++++++++++++++++++---------- appveyor.yml | 29 +++++++++++++++++++++++------ 2 files changed, 45 insertions(+), 16 deletions(-) diff --git a/.travis.yml b/.travis.yml index 239e8071d12..cd312691a22 100644 --- a/.travis.yml +++ b/.travis.yml @@ -24,16 +24,28 @@ cache: directories: - node_modules before_install: - # Skip updating shrinkwrap / lock - - "npm config set shrinkwrap false" - + # Configure npm + - | + # Skip updating shrinkwrap / lock + npm config set shrinkwrap false # Remove all non-test dependencies - - "npm rm --save-dev connect-redis" - + - | + # Remove example dependencies + npm rm --silent --save-dev connect-redis # Update Node.js modules - - "test ! -d node_modules || npm prune" - - "test ! -d node_modules || npm rebuild" + - | + # Prune and rebuild node_modules + if [[ -d node_modules ]]; then + npm prune + npm rebuild + fi script: - - "npm run test-ci" - - "npm run lint" -after_script: "npm install coveralls@2.10.0 && cat ./coverage/lcov.info | coveralls" + # Run test script + - npm run test-ci + # Run linting + - npm run lint +after_script: + - | + # Upload coverage to coveralls + npm install --save-dev coveralls@2.10.0 + coveralls < ./coverage/lcov.info diff --git a/appveyor.yml b/appveyor.yml index 6e77e88bcdd..fd5dcea0a6d 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -13,18 +13,35 @@ environment: cache: - node_modules install: + # Install Node.js - ps: >- try { Install-Product node $env:nodejs_version -ErrorAction Stop } catch { Update-NodeJsInstallation (Get-NodeJsLatestBuild $env:nodejs_version) } - - npm config set shrinkwrap false - - npm rm --save-dev connect-redis - - if exist node_modules npm prune - - if exist node_modules npm rebuild + # Configure npm + - ps: | + # Skip updating shrinkwrap / lock + npm config set shrinkwrap false + # Remove all non-test dependencies + - ps: | + # Remove example dependencies + npm rm --silent --save-dev connect-redis + # Update Node.js modules + - ps: | + # Prune & rebuild node_modules + if (Test-Path -Path node_modules) { + npm prune + npm rebuild + } + # Install Node.js modules - npm install build: off test_script: - - node --version - - npm --version + # Output version data + - ps: | + node --version + npm --version + # Run test script - npm run test-ci + # Run linting - npm run lint version: "{build}" From f07f368fba5d91a5a80bff80c360bd5d66ed8116 Mon Sep 17 00:00:00 2001 From: Douglas Christopher Wilson Date: Fri, 21 Sep 2018 23:16:17 -0400 Subject: [PATCH 017/270] build: mocha@5.2.0 --- .travis.yml | 7 +++++++ appveyor.yml | 7 +++++++ package.json | 10 +++++----- test/mocha.opts | 1 - 4 files changed, 19 insertions(+), 6 deletions(-) diff --git a/.travis.yml b/.travis.yml index cd312691a22..a4f644190a5 100644 --- a/.travis.yml +++ b/.travis.yml @@ -32,6 +32,13 @@ before_install: - | # Remove example dependencies npm rm --silent --save-dev connect-redis + # Setup Node.js version-specific dependencies + - | + # mocha for testing + # - use 3.x for Node.js < 6 + if [[ "$(cut -d. -f1 <<< "$TRAVIS_NODE_VERSION")" -lt 6 ]]; then + npm install --silent --save-dev mocha@3.5.3 + fi # Update Node.js modules - | # Prune and rebuild node_modules diff --git a/appveyor.yml b/appveyor.yml index fd5dcea0a6d..bb954116f16 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -25,6 +25,13 @@ install: - ps: | # Remove example dependencies npm rm --silent --save-dev connect-redis + # Setup Node.js version-specific dependencies + - ps: | + # mocha for testing + # - use 3.x for Node.js < 6 + if ($env:nodejs_version.split(".")[0] -lt 6) { + npm install --silent --save-dev mocha@3.5.3 + } # Update Node.js modules - ps: | # Prune & rebuild node_modules diff --git a/package.json b/package.json index 45faac1c6ba..bbd79fbf887 100644 --- a/package.json +++ b/package.json @@ -69,7 +69,7 @@ "istanbul": "0.4.5", "marked": "0.5.0", "method-override": "3.0.0", - "mocha": "3.5.3", + "mocha": "5.2.0", "morgan": "1.9.1", "multiparty": "4.2.1", "pbkdf2-password": "1.2.1", @@ -90,9 +90,9 @@ ], "scripts": { "lint": "eslint .", - "test": "mocha --require test/support/env --reporter spec --bail --check-leaks --no-exit test/ test/acceptance/", - "test-ci": "istanbul cover node_modules/mocha/bin/_mocha --report lcovonly -- --require test/support/env --reporter spec --check-leaks --no-exit test/ test/acceptance/", - "test-cov": "istanbul cover node_modules/mocha/bin/_mocha -- --require test/support/env --reporter dot --check-leaks --no-exit test/ test/acceptance/", - "test-tap": "mocha --require test/support/env --reporter tap --check-leaks --no-exit test/ test/acceptance/" + "test": "mocha --require test/support/env --reporter spec --bail --check-leaks test/ test/acceptance/", + "test-ci": "istanbul cover node_modules/mocha/bin/_mocha --report lcovonly -- --require test/support/env --reporter spec --check-leaks test/ test/acceptance/", + "test-cov": "istanbul cover node_modules/mocha/bin/_mocha -- --require test/support/env --reporter dot --check-leaks test/ test/acceptance/", + "test-tap": "mocha --require test/support/env --reporter tap --check-leaks test/ test/acceptance/" } } diff --git a/test/mocha.opts b/test/mocha.opts index 24d45f5902f..1e065ec52d9 100644 --- a/test/mocha.opts +++ b/test/mocha.opts @@ -1,3 +1,2 @@ --require should --slow 20 ---growl From 451ee5d9c17b8abd6859b939a5edfa083a61127d Mon Sep 17 00:00:00 2001 From: Douglas Christopher Wilson Date: Mon, 24 Sep 2018 23:40:21 -0400 Subject: [PATCH 018/270] build: supertest@3.3.0 --- .travis.yml | 6 ++++++ appveyor.yml | 6 ++++++ package.json | 2 +- test/app.router.js | 8 ++------ test/res.download.js | 13 ++++++++++++- test/res.redirect.js | 15 +++++++++++++-- test/res.send.js | 24 ++++++++++++++++++++++-- test/res.sendFile.js | 19 +++++++++++++++++-- 8 files changed, 79 insertions(+), 14 deletions(-) diff --git a/.travis.yml b/.travis.yml index a4f644190a5..ebeed7008dd 100644 --- a/.travis.yml +++ b/.travis.yml @@ -39,6 +39,12 @@ before_install: if [[ "$(cut -d. -f1 <<< "$TRAVIS_NODE_VERSION")" -lt 6 ]]; then npm install --silent --save-dev mocha@3.5.3 fi + - | + # supertest for http calls + # - use 2.0.0 for Node.js < 4 + if [[ "$(cut -d. -f1 <<< "$TRAVIS_NODE_VERSION")" -lt 4 ]]; then + npm install --silent --save-dev supertest@2.0.0 + fi # Update Node.js modules - | # Prune and rebuild node_modules diff --git a/appveyor.yml b/appveyor.yml index bb954116f16..fc3582e4a5a 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -32,6 +32,12 @@ install: if ($env:nodejs_version.split(".")[0] -lt 6) { npm install --silent --save-dev mocha@3.5.3 } + - ps: | + # supertest for http calls + # - use 2.0.0 for Node.js < 4 + if ($env:nodejs_version.split(".")[0] -lt 4) { + npm install --silent --save-dev supertest@2.0.0 + } # Update Node.js modules - ps: | # Prune & rebuild node_modules diff --git a/package.json b/package.json index bbd79fbf887..2ffd015a6a0 100644 --- a/package.json +++ b/package.json @@ -74,7 +74,7 @@ "multiparty": "4.2.1", "pbkdf2-password": "1.2.1", "should": "13.2.3", - "supertest": "2.0.0", + "supertest": "3.3.0", "connect-redis": "~2.4.1", "vhost": "~3.0.2" }, diff --git a/test/app.router.js b/test/app.router.js index c4bfc9b952a..a6c8cef202a 100644 --- a/test/app.router.js +++ b/test/app.router.js @@ -41,16 +41,12 @@ describe('app.router', function(){ var app = express(); app[method]('/foo', function(req, res){ - if (method === 'head') { - res.end(); - } else { - res.end(method); - } + res.send(method) }); request(app) [method]('/foo') - .expect(method === 'head' ? '' : method, done) + .expect(200, done) }) it('should reject numbers for app.' + method, function(){ diff --git a/test/res.download.js b/test/res.download.js index 30215bf6764..084b3c7164d 100644 --- a/test/res.download.js +++ b/test/res.download.js @@ -1,6 +1,7 @@ var after = require('after'); var assert = require('assert'); +var Buffer = require('safe-buffer').Buffer var express = require('..'); var request = require('supertest'); @@ -104,7 +105,7 @@ describe('res', function(){ .expect(200) .expect('Content-Disposition', 'attachment; filename="document"') .expect('Cache-Control', 'public, max-age=14400') - .expect('tobi') + .expect(shouldHaveBody(Buffer.from('tobi'))) .end(done) }) @@ -185,6 +186,16 @@ describe('res', function(){ }) }) +function shouldHaveBody (buf) { + return function (res) { + var body = !Buffer.isBuffer(res.body) + ? Buffer.from(res.text) + : res.body + assert.ok(body, 'response has body') + assert.strictEqual(body.toString('hex'), buf.toString('hex')) + } +} + function shouldNotHaveHeader(header) { return function (res) { assert.ok(!(header.toLowerCase() in res.headers), 'should not have header ' + header); diff --git a/test/res.redirect.js b/test/res.redirect.js index 755bb1c1c6c..c07df5dd2c4 100644 --- a/test/res.redirect.js +++ b/test/res.redirect.js @@ -1,4 +1,5 @@ +var assert = require('assert') var express = require('..'); var request = require('supertest'); var utils = require('./support/utils'); @@ -85,8 +86,10 @@ describe('res', function(){ request(app) .head('/') + .expect(302) .expect('Location', 'http://google.com') - .expect(302, '', done) + .expect(shouldNotHaveBody()) + .end(done) }) }) @@ -197,10 +200,18 @@ describe('res', function(){ request(app) .get('/') .set('Accept', 'application/octet-stream') + .expect(302) .expect('location', 'http://google.com') .expect('content-length', '0') .expect(utils.shouldNotHaveHeader('Content-Type')) - .expect(302, '', done) + .expect(shouldNotHaveBody()) + .end(done) }) }) }) + +function shouldNotHaveBody () { + return function (res) { + assert.ok(res.text === '' || res.text === undefined) + } +} diff --git a/test/res.send.js b/test/res.send.js index 13658fe6b01..b836b5e4dcb 100644 --- a/test/res.send.js +++ b/test/res.send.js @@ -188,8 +188,10 @@ describe('res', function(){ request(app) .get('/') + .expect(200) .expect('Content-Type', 'application/octet-stream') - .expect(200, 'hello', done); + .expect(shouldHaveBody(Buffer.from('hello'))) + .end(done) }) it('should set ETag', function (done) { @@ -257,7 +259,9 @@ describe('res', function(){ request(app) .head('/') - .expect('', done); + .expect(200) + .expect(shouldNotHaveBody()) + .end(done) }) }) @@ -573,3 +577,19 @@ describe('res', function(){ }) }) }) + +function shouldHaveBody (buf) { + return function (res) { + var body = !Buffer.isBuffer(res.body) + ? Buffer.from(res.text) + : res.body + assert.ok(body, 'response has body') + assert.strictEqual(body.toString('hex'), buf.toString('hex')) + } +} + +function shouldNotHaveBody () { + return function (res) { + assert.ok(res.text === '' || res.text === undefined) + } +} diff --git a/test/res.sendFile.js b/test/res.sendFile.js index 46cf98bd3b9..d7585b7704c 100644 --- a/test/res.sendFile.js +++ b/test/res.sendFile.js @@ -1,5 +1,6 @@ var after = require('after'); +var Buffer = require('safe-buffer').Buffer var express = require('../') , request = require('supertest') , assert = require('assert'); @@ -155,7 +156,9 @@ describe('res', function(){ request(app) .get('/') - .expect(200, 'tobi', done); + .expect(200) + .expect(shouldHaveBody(Buffer.from('tobi'))) + .end(done) }); }); @@ -548,7 +551,9 @@ describe('res', function(){ request(app) .get('/') - .expect(200, 'tobi', done); + .expect(200) + .expect(shouldHaveBody(Buffer.from('tobi'))) + .end(done) }) it('should accept headers option', function(done){ @@ -801,3 +806,13 @@ function createApp(path, options, fn) { return app; } + +function shouldHaveBody (buf) { + return function (res) { + var body = !Buffer.isBuffer(res.body) + ? Buffer.from(res.text) + : res.body + assert.ok(body, 'response has body') + assert.strictEqual(body.toString('hex'), buf.toString('hex')) + } +} From 62a59b6ace6c1cb34f9adf2d433ac57d3c826ce4 Mon Sep 17 00:00:00 2001 From: Douglas Christopher Wilson Date: Thu, 27 Sep 2018 18:09:27 -0400 Subject: [PATCH 019/270] build: update example dependencies --- package.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/package.json b/package.json index 2ffd015a6a0..6118573572f 100644 --- a/package.json +++ b/package.json @@ -60,6 +60,7 @@ }, "devDependencies": { "after": "0.8.2", + "connect-redis": "3.4.0", "cookie-parser": "~1.4.3", "cookie-session": "1.3.2", "ejs": "2.6.1", @@ -67,7 +68,7 @@ "express-session": "1.15.6", "hbs": "4.0.1", "istanbul": "0.4.5", - "marked": "0.5.0", + "marked": "0.5.1", "method-override": "3.0.0", "mocha": "5.2.0", "morgan": "1.9.1", @@ -75,7 +76,6 @@ "pbkdf2-password": "1.2.1", "should": "13.2.3", "supertest": "3.3.0", - "connect-redis": "~2.4.1", "vhost": "~3.0.2" }, "engines": { From dc538f6e810bd462c98ee7e6aae24c64d4b1da93 Mon Sep 17 00:00:00 2001 From: Douglas Christopher Wilson Date: Wed, 10 Oct 2018 23:50:45 -0400 Subject: [PATCH 020/270] 4.16.4 --- History.md | 4 ++-- package.json | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/History.md b/History.md index 2d902e94d61..2f6eab101ae 100644 --- a/History.md +++ b/History.md @@ -1,5 +1,5 @@ -unreleased -========== +4.16.4 / 2018-10-10 +=================== * Fix issue where `"Request aborted"` may be logged in `res.sendfile` * Fix JSDoc for `Router` constructor diff --git a/package.json b/package.json index 6118573572f..74196ad68e2 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "express", "description": "Fast, unopinionated, minimalist web framework", - "version": "4.16.3", + "version": "4.16.4", "author": "TJ Holowaychuk ", "contributors": [ "Aaron Heckmann ", From d0421ac7e1f897e15a2f7a9328e9bfd938b95a9f Mon Sep 17 00:00:00 2001 From: Douglas Christopher Wilson Date: Fri, 26 Oct 2018 23:34:00 -0400 Subject: [PATCH 021/270] tests: use supertest to perform assertions --- test/app.router.js | 24 +++++++++--------------- test/res.cookie.js | 7 ++----- test/res.locals.js | 10 ++++------ 3 files changed, 15 insertions(+), 26 deletions(-) diff --git a/test/app.router.js b/test/app.router.js index a6c8cef202a..d716ea4b046 100644 --- a/test/app.router.js +++ b/test/app.router.js @@ -152,15 +152,12 @@ describe('app.router', function(){ app.use(function(req, res, next){ calls.push('after'); - res.end(); + res.json(calls) }); request(app) .get('/') - .end(function(res){ - calls.should.eql(['before', 'GET /', 'after']) - done(); - }) + .expect(200, ['before', 'GET /', 'after'], done) }) describe('when given a regexp', function(){ @@ -891,15 +888,12 @@ describe('app.router', function(){ app.get('/foo', function(req, res, next){ calls.push('/foo 2'); - res.end('done'); + res.json(calls) }); request(app) .get('/foo') - .expect('done', function(){ - calls.should.eql(['/foo/:bar?', '/foo', '/foo 2']); - done(); - }) + .expect(200, ['/foo/:bar?', '/foo', '/foo 2'], done) }) }) @@ -982,15 +976,15 @@ describe('app.router', function(){ }); app.use(function(err, req, res, next){ - res.end(err.message); + res.json({ + calls: calls, + error: err.message + }) }) request(app) .get('/foo') - .expect('fail', function(){ - calls.should.eql(['/foo/:bar?', '/foo']); - done(); - }) + .expect(200, { calls: ['/foo/:bar?', '/foo'], error: 'fail' }, done) }) it('should call handler in same route, if exists', function(done){ diff --git a/test/res.cookie.js b/test/res.cookie.js index 4eeaaf094ad..271a0969e62 100644 --- a/test/res.cookie.js +++ b/test/res.cookie.js @@ -108,15 +108,12 @@ describe('res', function(){ app.use(function(req, res){ res.cookie('name', 'tobi', options) - res.end(); + res.json(options) }); request(app) .get('/') - .end(function(err, res){ - options.should.eql(optionsCopy); - done(); - }) + .expect(200, optionsCopy, done) }) }) diff --git a/test/res.locals.js b/test/res.locals.js index 3c83e66c54f..a1c819667a3 100644 --- a/test/res.locals.js +++ b/test/res.locals.js @@ -8,13 +8,12 @@ describe('res', function(){ var app = express(); app.use(function(req, res){ - Object.keys(res.locals).should.eql([]); - res.end(); + res.json(res.locals) }); request(app) .get('/') - .expect(200, done); + .expect(200, {}, done) }) }) @@ -30,12 +29,11 @@ describe('res', function(){ }); app.use(function(req, res){ - res.locals.foo.should.equal('bar'); - res.end(); + res.json(res.locals) }); request(app) .get('/') - .expect(200, done); + .expect(200, { foo: 'bar' }, done) }) }) From a6b119d27a2f1703d51d1938e6fe98b0ee2d5651 Mon Sep 17 00:00:00 2001 From: Douglas Christopher Wilson Date: Sat, 27 Oct 2018 00:05:00 -0400 Subject: [PATCH 022/270] build: coveralls@2.12.0 --- .travis.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index ebeed7008dd..a36ad43c97b 100644 --- a/.travis.yml +++ b/.travis.yml @@ -60,5 +60,5 @@ script: after_script: - | # Upload coverage to coveralls - npm install --save-dev coveralls@2.10.0 + npm install --save-dev coveralls@2.12.0 coveralls < ./coverage/lcov.info From 6295b4592014515e137c17e854f83d1c0274198a Mon Sep 17 00:00:00 2001 From: Douglas Christopher Wilson Date: Sat, 27 Oct 2018 00:50:58 -0400 Subject: [PATCH 023/270] build: test against Node.js 11.x nightly --- .travis.yml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.travis.yml b/.travis.yml index a36ad43c97b..a49b22edcf3 100644 --- a/.travis.yml +++ b/.travis.yml @@ -16,6 +16,8 @@ matrix: env: "NVM_NODEJS_ORG_MIRROR=https://nodejs.org/download/nightly" - node_js: "10" env: "NVM_NODEJS_ORG_MIRROR=https://nodejs.org/download/nightly" + - node_js: "11" + env: "NVM_NODEJS_ORG_MIRROR=https://nodejs.org/download/nightly" allow_failures: # Allow the nightly installs to fail - env: "NVM_NODEJS_ORG_MIRROR=https://nodejs.org/download/nightly" From 003459b795b3ab2ae97c2131585b0560c1d35716 Mon Sep 17 00:00:00 2001 From: Nacim Goura Date: Tue, 10 Apr 2018 11:33:43 +0200 Subject: [PATCH 024/270] build: support Node.js 9.x closes #3617 --- .travis.yml | 3 +-- appveyor.yml | 1 + 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.travis.yml b/.travis.yml index a49b22edcf3..aad455e48ba 100644 --- a/.travis.yml +++ b/.travis.yml @@ -10,10 +10,9 @@ node_js: - "6.14" - "7.10" - "8.12" + - "9.11" matrix: include: - - node_js: "9" - env: "NVM_NODEJS_ORG_MIRROR=https://nodejs.org/download/nightly" - node_js: "10" env: "NVM_NODEJS_ORG_MIRROR=https://nodejs.org/download/nightly" - node_js: "11" diff --git a/appveyor.yml b/appveyor.yml index fc3582e4a5a..0a911723cf2 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -10,6 +10,7 @@ environment: - nodejs_version: "6.14" - nodejs_version: "7.10" - nodejs_version: "8.12" + - nodejs_version: "9.11" cache: - node_modules install: From 44e539e1dcdc010638812fc96f541da3f02d35de Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Felix=20Bu=CC=88nemann?= Date: Wed, 16 May 2018 18:27:06 +0200 Subject: [PATCH 025/270] build: support Node.js 10.x closes #3617 --- .travis.yml | 3 +-- appveyor.yml | 1 + 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.travis.yml b/.travis.yml index aad455e48ba..c802e4fd3a7 100644 --- a/.travis.yml +++ b/.travis.yml @@ -11,10 +11,9 @@ node_js: - "7.10" - "8.12" - "9.11" + - "10.12" matrix: include: - - node_js: "10" - env: "NVM_NODEJS_ORG_MIRROR=https://nodejs.org/download/nightly" - node_js: "11" env: "NVM_NODEJS_ORG_MIRROR=https://nodejs.org/download/nightly" allow_failures: diff --git a/appveyor.yml b/appveyor.yml index 0a911723cf2..4006a5e51d9 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -11,6 +11,7 @@ environment: - nodejs_version: "7.10" - nodejs_version: "8.12" - nodejs_version: "9.11" + - nodejs_version: "10.12" cache: - node_modules install: From 6bcdfef6ad148672872e4f5930a01a5a45dd9df0 Mon Sep 17 00:00:00 2001 From: void Date: Sun, 4 Mar 2018 04:56:32 +0400 Subject: [PATCH 026/270] Improve error message for non-strings to res.sendFile closes #3582 --- History.md | 5 +++++ lib/response.js | 4 ++++ test/res.sendFile.js | 8 ++++++++ 3 files changed, 17 insertions(+) diff --git a/History.md b/History.md index 2f6eab101ae..6a0699421ad 100644 --- a/History.md +++ b/History.md @@ -1,3 +1,8 @@ +unreleased +========== + + * Improve error message for non-strings to `res.sendFile` + 4.16.4 / 2018-10-10 =================== diff --git a/lib/response.js b/lib/response.js index 2e445ac02c5..11adeb614a9 100644 --- a/lib/response.js +++ b/lib/response.js @@ -411,6 +411,10 @@ res.sendFile = function sendFile(path, options, callback) { throw new TypeError('path argument is required to res.sendFile'); } + if (typeof path !== 'string') { + throw new TypeError('path must be a string to res.sendFile') + } + // support function as second arg if (typeof options === 'function') { done = options; diff --git a/test/res.sendFile.js b/test/res.sendFile.js index d7585b7704c..5f494f1e0bc 100644 --- a/test/res.sendFile.js +++ b/test/res.sendFile.js @@ -20,6 +20,14 @@ describe('res', function(){ .expect(500, /path.*required/, done); }); + it('should error for non-string path', function (done) { + var app = createApp(42) + + request(app) + .get('/') + .expect(500, /TypeError: path must be a string to res.sendFile/, done) + }) + it('should transfer a file', function (done) { var app = createApp(path.resolve(fixtures, 'name.txt')); From 8da51108e7bb501344c537d3f1f846a7477ae329 Mon Sep 17 00:00:00 2001 From: Joshua Caron Date: Thu, 12 Nov 2015 13:33:06 -0500 Subject: [PATCH 027/270] Improve error message for null/undefined to res.status closes #2795 closes #2797 closes #3111 --- History.md | 1 + lib/response.js | 4 ++++ test/res.status.js | 32 ++++++++++++++++++++++++++++++++ 3 files changed, 37 insertions(+) diff --git a/History.md b/History.md index 6a0699421ad..35147d390d3 100644 --- a/History.md +++ b/History.md @@ -2,6 +2,7 @@ unreleased ========== * Improve error message for non-strings to `res.sendFile` + * Improve error message for `null`/`undefined` to `res.status` 4.16.4 / 2018-10-10 =================== diff --git a/lib/response.js b/lib/response.js index 11adeb614a9..60f8979e859 100644 --- a/lib/response.js +++ b/lib/response.js @@ -64,6 +64,10 @@ var charsetRegExp = /;\s*charset\s*=/; */ res.status = function status(code) { + if (code === undefined || code === null) { + throw new TypeError('code argument is required to res.status') + } + this.statusCode = code; return this; }; diff --git a/test/res.status.js b/test/res.status.js index 8c173a645c5..3f928ec0b0b 100644 --- a/test/res.status.js +++ b/test/res.status.js @@ -16,5 +16,37 @@ describe('res', function(){ .expect('Created') .expect(201, done); }) + + describe('when code is undefined', function () { + it('should throw a TypeError', function (done) { + var app = express() + + app.use(function (req, res) { + res.status(undefined).send('OK') + }) + + request(app) + .get('/') + .expect(500) + .expect(/TypeError: code argument is required to res.status/) + .end(done) + }) + }) + + describe('when code is null', function () { + it('should throw a TypeError', function (done) { + var app = express() + + app.use(function (req, res) { + res.status(null).send('OK') + }) + + request(app) + .get('/') + .expect(500) + .expect(/TypeError: code argument is required to res.status/) + .end(done) + }) + }) }) }) From b93ffd4bdc09c3af925eed80c28bd37f63bb3cfc Mon Sep 17 00:00:00 2001 From: Horatiu Eugen Vlad Date: Sun, 3 Dec 2017 19:52:46 +0100 Subject: [PATCH 028/270] Support multiple hosts in X-Forwarded-Host fixes #3494 closes #3495 --- History.md | 1 + lib/request.js | 4 ++++ test/req.hostname.js | 50 ++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 55 insertions(+) diff --git a/History.md b/History.md index 35147d390d3..c29a4490bd4 100644 --- a/History.md +++ b/History.md @@ -3,6 +3,7 @@ unreleased * Improve error message for non-strings to `res.sendFile` * Improve error message for `null`/`undefined` to `res.status` + * Support multiple hosts in `X-Forwarded-Host` 4.16.4 / 2018-10-10 =================== diff --git a/lib/request.js b/lib/request.js index 8bb86a9acc4..a9400ef99de 100644 --- a/lib/request.js +++ b/lib/request.js @@ -430,6 +430,10 @@ defineGetter(req, 'hostname', function hostname(){ if (!host || !trust(this.connection.remoteAddress, 0)) { host = this.get('Host'); + } else if (host.indexOf(',') !== -1) { + // Note: X-Forwarded-Host is normally only ever a + // single value, but this is to be safe. + host = host.substring(0, host.indexOf(',')).trimRight() } if (!host) return; diff --git a/test/req.hostname.js b/test/req.hostname.js index 816cd597990..09bfb899898 100644 --- a/test/req.hostname.js +++ b/test/req.hostname.js @@ -116,6 +116,56 @@ describe('req', function(){ .set('Host', 'example.com') .expect('example.com', done); }) + + describe('when multiple X-Forwarded-Host', function () { + it('should use the first value', function (done) { + var app = express() + + app.enable('trust proxy') + + app.use(function (req, res) { + res.send(req.hostname) + }) + + request(app) + .get('/') + .set('Host', 'localhost') + .set('X-Forwarded-Host', 'example.com, foobar.com') + .expect(200, 'example.com', done) + }) + + it('should remove OWS around comma', function (done) { + var app = express() + + app.enable('trust proxy') + + app.use(function (req, res) { + res.send(req.hostname) + }) + + request(app) + .get('/') + .set('Host', 'localhost') + .set('X-Forwarded-Host', 'example.com , foobar.com') + .expect(200, 'example.com', done) + }) + + it('should strip port number', function (done) { + var app = express() + + app.enable('trust proxy') + + app.use(function (req, res) { + res.send(req.hostname) + }) + + request(app) + .get('/') + .set('Host', 'localhost') + .set('X-Forwarded-Host', 'example.com:8080 , foobar.com:8888') + .expect(200, 'example.com', done) + }) + }) }) describe('when "trust proxy" is disabled', function(){ From 95c31f7041fe31b24175ce9a6537a0d0d6b807f7 Mon Sep 17 00:00:00 2001 From: HubCodes Date: Thu, 13 Dec 2018 16:04:27 +0900 Subject: [PATCH 029/270] docs: fix typo in contributing closes #3827 --- Contributing.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Contributing.md b/Contributing.md index 41386568d64..f84c0138cb0 100644 --- a/Contributing.md +++ b/Contributing.md @@ -19,7 +19,7 @@ expertise to resolve rare disputes. Log an issue for any question or problem you might have. When in doubt, log an issue, and any additional policies about what to include will be provided in the responses. The only -exception is security dislosures which should be sent privately. +exception is security disclosures which should be sent privately. Committers may direct you to another repository, ask for additional clarifications, and add appropriate metadata before the issue is addressed. From 0ae10bb15471745795a44d9316e324b697725524 Mon Sep 17 00:00:00 2001 From: Austin Scriver Date: Mon, 26 Nov 2018 20:00:47 -0700 Subject: [PATCH 030/270] docs: fix typos in history closes #3810 --- History.md | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/History.md b/History.md index c29a4490bd4..20cee356455 100644 --- a/History.md +++ b/History.md @@ -301,7 +301,7 @@ unreleased - Fix including type extensions in parameters in `Accept` parsing - Fix parsing `Accept` parameters with quoted equals - Fix parsing `Accept` parameters with quoted semicolons - - Many performance improvments + - Many performance improvements - deps: mime-types@~2.1.11 - deps: negotiator@0.6.1 * deps: content-type@~1.0.2 @@ -316,7 +316,7 @@ unreleased - perf: enable strict mode - perf: hoist regular expression - perf: use for loop in parse - - perf: use string concatination for serialization + - perf: use string concatenation for serialization * deps: finalhandler@0.5.0 - Change invalid or non-numeric status code to 500 - Overwrite status message to match set status code @@ -326,7 +326,7 @@ unreleased * deps: proxy-addr@~1.1.2 - Fix accepting various invalid netmasks - Fix IPv6-mapped IPv4 validation edge cases - - IPv4 netmasks must be contingous + - IPv4 netmasks must be contiguous - IPv6 addresses cannot be used as a netmask - deps: ipaddr.js@1.1.1 * deps: qs@6.2.0 @@ -1104,13 +1104,13 @@ unreleased - deps: negotiator@0.4.6 * deps: debug@1.0.2 * deps: send@0.4.3 - - Do not throw un-catchable error on file open race condition + - Do not throw uncatchable error on file open race condition - Use `escape-html` for HTML escaping - deps: debug@1.0.2 - deps: finished@1.2.2 - deps: fresh@0.2.2 * deps: serve-static@1.2.3 - - Do not throw un-catchable error on file open race condition + - Do not throw uncatchable error on file open race condition - deps: send@0.4.3 4.4.2 / 2014-06-09 @@ -1990,7 +1990,7 @@ unreleased - deps: serve-static@1.2.3 * deps: debug@1.0.2 * deps: send@0.4.3 - - Do not throw un-catchable error on file open race condition + - Do not throw uncatchable error on file open race condition - Use `escape-html` for HTML escaping - deps: debug@1.0.2 - deps: finished@1.2.2 @@ -3175,7 +3175,7 @@ Shaw] * Updated haml submodule * Changed ETag; removed inode, modified time only * Fixed LF to CRLF for setting multiple cookies - * Fixed cookie complation; values are now urlencoded + * Fixed cookie compilation; values are now urlencoded * Fixed cookies parsing; accepts quoted values and url escaped cookies 0.11.0 / 2010-05-06 @@ -3370,7 +3370,7 @@ Shaw] * Added "plot" format option for Profiler (for gnuplot processing) * Added request number to Profiler plugin - * Fixed binary encoding for multi-part file uploads, was previously defaulting to UTF8 + * Fixed binary encoding for multipart file uploads, was previously defaulting to UTF8 * Fixed issue with routes not firing when not files are present. Closes #184 * Fixed process.Promise -> events.Promise @@ -3416,7 +3416,7 @@ Shaw] * Updated sample chat app to show messages on load * Updated libxmljs parseString -> parseHtmlString * Fixed `make init` to work with older versions of git - * Fixed specs can now run independent specs for those who cant build deps. Closes #127 + * Fixed specs can now run independent specs for those who can't build deps. Closes #127 * Fixed issues introduced by the node url module changes. Closes 126. * Fixed two assertions failing due to Collection#keys() returning strings * Fixed faulty Collection#toArray() spec due to keys() returning strings From 02f3933b6962114cf46c637105db7983d32a156a Mon Sep 17 00:00:00 2001 From: Alvin Smith Date: Thu, 29 Nov 2018 21:02:55 +1300 Subject: [PATCH 031/270] examples: minor fixes to some examples closes #3812 --- examples/downloads/index.js | 2 +- examples/mvc/public/style.css | 2 +- examples/static-files/public/js/app.js | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/examples/downloads/index.js b/examples/downloads/index.js index e6f3fa9db69..5f0772697c1 100644 --- a/examples/downloads/index.js +++ b/examples/downloads/index.js @@ -21,7 +21,7 @@ app.get('/files/:file(*)', function(req, res, next){ res.download(filePath, function (err) { if (!err) return; // file sent - if (err && err.status !== 404) return next(err); // non-404 error + if (err.status !== 404) return next(err); // non-404 error // file for download not found res.statusCode = 404; res.send('Cant find that file, sorry!'); diff --git a/examples/mvc/public/style.css b/examples/mvc/public/style.css index 69fde2e23aa..8a23f9d41c4 100644 --- a/examples/mvc/public/style.css +++ b/examples/mvc/public/style.css @@ -1,6 +1,6 @@ body { padding: 50px; - font: 16px "Helvetica Neue", Helvetica, Arial; + font: 16px "Helvetica Neue", Helvetica, Arial, sans-serif; } a { color: #107aff; diff --git a/examples/static-files/public/js/app.js b/examples/static-files/public/js/app.js index 257cc5642cb..775eb734b02 100644 --- a/examples/static-files/public/js/app.js +++ b/examples/static-files/public/js/app.js @@ -1 +1 @@ -foo +// foo From 186a206a0aed799699e6a7400aed9aeef31c21e9 Mon Sep 17 00:00:00 2001 From: Ciro Santilli Date: Tue, 5 Feb 2019 09:39:46 +0000 Subject: [PATCH 032/270] docs: add listening address to example closes #3873 --- Readme.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/Readme.md b/Readme.md index 582e8958c59..9053d79006d 100644 --- a/Readme.md +++ b/Readme.md @@ -90,6 +90,8 @@ $ npm install $ npm start ``` + View the website at: http://localhost:3000 + ## Philosophy The Express philosophy is to provide small, robust tooling for HTTP servers, making From 6f12eee8abcfdd672c7a3d638d3dbf744a6b1801 Mon Sep 17 00:00:00 2001 From: Louis Date: Thu, 17 Jan 2019 18:33:01 +0100 Subject: [PATCH 033/270] docs: fix typo in jsdoc comment closes #3859 --- lib/response.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/response.js b/lib/response.js index 60f8979e859..c1514901c57 100644 --- a/lib/response.js +++ b/lib/response.js @@ -822,7 +822,7 @@ res.clearCookie = function clearCookie(name, options) { * // "Remember Me" for 15 minutes * res.cookie('rememberme', '1', { expires: new Date(Date.now() + 900000), httpOnly: true }); * - * // save as above + * // same as above * res.cookie('rememberme', '1', { maxAge: 900000, httpOnly: true }) * * @param {String} name From b9b1b19758b0996680100c65ae87128d623c5f7e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EA=B9=80=EC=A0=95=ED=99=98?= Date: Fri, 1 Feb 2019 09:56:14 +0900 Subject: [PATCH 034/270] tests: fix typos in descriptions closes #3875 --- test/app.router.js | 2 +- test/req.acceptsCharset.js | 4 ++-- test/req.acceptsCharsets.js | 4 ++-- test/req.acceptsEncodings.js | 2 +- test/req.query.js | 2 +- test/res.download.js | 4 ++-- 6 files changed, 9 insertions(+), 9 deletions(-) diff --git a/test/app.router.js b/test/app.router.js index d716ea4b046..5a31b5fb90c 100644 --- a/test/app.router.js +++ b/test/app.router.js @@ -567,7 +567,7 @@ describe('app.router', function(){ .expect('/user/tobi.json', done) }) - it('should decore the capture', function (done) { + it('should decode the capture', function (done) { var app = express() app.get('*', function (req, res) { diff --git a/test/req.acceptsCharset.js b/test/req.acceptsCharset.js index 0d0ed8b5e41..f7d0cc0e300 100644 --- a/test/req.acceptsCharset.js +++ b/test/req.acceptsCharset.js @@ -18,8 +18,8 @@ describe('req', function(){ }) }) - describe('when Accept-Charset is not present', function(){ - it('should return true when present', function(done){ + describe('when Accept-Charset is present', function () { + it('should return true', function (done) { var app = express(); app.use(function(req, res, next){ diff --git a/test/req.acceptsCharsets.js b/test/req.acceptsCharsets.js index 2f4574c5244..d1c459174a9 100644 --- a/test/req.acceptsCharsets.js +++ b/test/req.acceptsCharsets.js @@ -18,8 +18,8 @@ describe('req', function(){ }) }) - describe('when Accept-Charset is not present', function(){ - it('should return true when present', function(done){ + describe('when Accept-Charset is present', function () { + it('should return true', function (done) { var app = express(); app.use(function(req, res, next){ diff --git a/test/req.acceptsEncodings.js b/test/req.acceptsEncodings.js index aba8ea5fbeb..a5cf747d41c 100644 --- a/test/req.acceptsEncodings.js +++ b/test/req.acceptsEncodings.js @@ -3,7 +3,7 @@ var express = require('../') , request = require('supertest'); describe('req', function(){ - describe('.acceptsEncodingss', function(){ + describe('.acceptsEncodings', function () { it('should be true if encoding accepted', function(done){ var app = express(); diff --git a/test/req.query.js b/test/req.query.js index d3d29abd16d..7819420ce01 100644 --- a/test/req.query.js +++ b/test/req.query.js @@ -70,7 +70,7 @@ describe('req', function(){ }); }); - describe('when "query parser" disabled', function () { + describe('when "query parser" enabled', function () { it('should not parse complex keys', function (done) { var app = createApp(true); diff --git a/test/res.download.js b/test/res.download.js index 084b3c7164d..cf3b3ca53e1 100644 --- a/test/res.download.js +++ b/test/res.download.js @@ -110,7 +110,7 @@ describe('res', function(){ }) describe('when options.headers contains Content-Disposition', function () { - it('should should be ignored', function (done) { + it('should be ignored', function (done) { var app = express() app.use(function (req, res) { @@ -130,7 +130,7 @@ describe('res', function(){ .end(done) }) - it('should should be ignored case-insensitively', function (done) { + it('should be ignored case-insensitively', function (done) { var app = express() app.use(function (req, res) { From 6eda52a3dc953f297942a98c333b609519141c49 Mon Sep 17 00:00:00 2001 From: Marcin Wanago Date: Wed, 30 Jan 2019 23:42:29 +0100 Subject: [PATCH 035/270] docs: use const in readme example fixes #3867 closes #3868 --- Readme.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Readme.md b/Readme.md index 9053d79006d..b25b240c7da 100644 --- a/Readme.md +++ b/Readme.md @@ -9,8 +9,8 @@ [![Test Coverage][coveralls-image]][coveralls-url] ```js -var express = require('express') -var app = express() +const express = require('express') +const app = express() app.get('/', function (req, res) { res.send('Hello World') From 8a97346eaf3a5e39ba8185b244af4918d2ca43b5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EA=B9=80=EC=A0=95=ED=99=98?= <6pack@madup.com> Date: Fri, 1 Feb 2019 21:33:07 +0900 Subject: [PATCH 036/270] tests: assert calls order in middleware basic tests closes #3878 --- test/middleware.basic.js | 2 ++ 1 file changed, 2 insertions(+) diff --git a/test/middleware.basic.js b/test/middleware.basic.js index ce59589230b..4616842ed60 100644 --- a/test/middleware.basic.js +++ b/test/middleware.basic.js @@ -1,4 +1,5 @@ +var assert = require('assert') var express = require('../'); var request = require('supertest'); @@ -33,6 +34,7 @@ describe('middleware', function(){ .set('Content-Type', 'application/json') .send('{"foo":"bar"}') .expect('Content-Type', 'application/json') + .expect(function () { assert.deepEqual(calls, ['one', 'two']) }) .expect(200, '{"foo":"bar"}', done) }) }) From 9e5d1a30c3671f99b5d80a231b697a311f5fe489 Mon Sep 17 00:00:00 2001 From: Douglas Christopher Wilson Date: Wed, 17 Apr 2019 10:44:27 -0400 Subject: [PATCH 037/270] build: test against Node.js 12.x nightly --- .travis.yml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.travis.yml b/.travis.yml index c802e4fd3a7..36e7e75e568 100644 --- a/.travis.yml +++ b/.travis.yml @@ -16,6 +16,8 @@ matrix: include: - node_js: "11" env: "NVM_NODEJS_ORG_MIRROR=https://nodejs.org/download/nightly" + - node_js: "12" + env: "NVM_NODEJS_ORG_MIRROR=https://nodejs.org/download/nightly" allow_failures: # Allow the nightly installs to fail - env: "NVM_NODEJS_ORG_MIRROR=https://nodejs.org/download/nightly" From cf5c813d2f6499be2d38a55a26dd5bd1b71b749c Mon Sep 17 00:00:00 2001 From: Douglas Christopher Wilson Date: Wed, 17 Apr 2019 15:51:33 -0400 Subject: [PATCH 038/270] build: hbs@4.0.4 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 74196ad68e2..0b8bec48632 100644 --- a/package.json +++ b/package.json @@ -66,7 +66,7 @@ "ejs": "2.6.1", "eslint": "2.13.1", "express-session": "1.15.6", - "hbs": "4.0.1", + "hbs": "4.0.4", "istanbul": "0.4.5", "marked": "0.5.1", "method-override": "3.0.0", From 4218d04183e0f7bd04f3db7d23b53d6d3857ed10 Mon Sep 17 00:00:00 2001 From: Douglas Christopher Wilson Date: Wed, 17 Apr 2019 15:58:26 -0400 Subject: [PATCH 039/270] build: marked@0.6.2 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 0b8bec48632..6dd72c1f7c0 100644 --- a/package.json +++ b/package.json @@ -68,7 +68,7 @@ "express-session": "1.15.6", "hbs": "4.0.4", "istanbul": "0.4.5", - "marked": "0.5.1", + "marked": "0.6.2", "method-override": "3.0.0", "mocha": "5.2.0", "morgan": "1.9.1", From 952484f73a84743c53abfc4b51a6614f2d1e13cd Mon Sep 17 00:00:00 2001 From: Douglas Christopher Wilson Date: Wed, 17 Apr 2019 16:00:02 -0400 Subject: [PATCH 040/270] deps: content-disposition@0.5.3 --- History.md | 1 + package.json | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/History.md b/History.md index 20cee356455..5343b0ba85d 100644 --- a/History.md +++ b/History.md @@ -4,6 +4,7 @@ unreleased * Improve error message for non-strings to `res.sendFile` * Improve error message for `null`/`undefined` to `res.status` * Support multiple hosts in `X-Forwarded-Host` + * deps: content-disposition@0.5.3 4.16.4 / 2018-10-10 =================== diff --git a/package.json b/package.json index 6dd72c1f7c0..9255d77d07b 100644 --- a/package.json +++ b/package.json @@ -30,7 +30,7 @@ "accepts": "~1.3.5", "array-flatten": "1.1.1", "body-parser": "1.18.3", - "content-disposition": "0.5.2", + "content-disposition": "0.5.3", "content-type": "~1.0.4", "cookie": "0.3.1", "cookie-signature": "1.0.6", From 50eb5e43774a78737a82405c17ac8ca3ff5532ff Mon Sep 17 00:00:00 2001 From: Douglas Christopher Wilson Date: Wed, 17 Apr 2019 16:05:17 -0400 Subject: [PATCH 041/270] deps: proxy-addr@~2.0.5 --- History.md | 2 ++ package.json | 2 +- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/History.md b/History.md index 5343b0ba85d..f8a5c0c0e10 100644 --- a/History.md +++ b/History.md @@ -5,6 +5,8 @@ unreleased * Improve error message for `null`/`undefined` to `res.status` * Support multiple hosts in `X-Forwarded-Host` * deps: content-disposition@0.5.3 + * deps: proxy-addr@~2.0.5 + - deps: ipaddr.js@1.9.0 4.16.4 / 2018-10-10 =================== diff --git a/package.json b/package.json index 9255d77d07b..92102c2a76f 100644 --- a/package.json +++ b/package.json @@ -46,7 +46,7 @@ "on-finished": "~2.3.0", "parseurl": "~1.3.2", "path-to-regexp": "0.1.7", - "proxy-addr": "~2.0.4", + "proxy-addr": "~2.0.5", "qs": "6.5.2", "range-parser": "~1.2.0", "safe-buffer": "5.1.2", From 03341204ff13fb35ac7082adf3dd694081ab68d3 Mon Sep 17 00:00:00 2001 From: Douglas Christopher Wilson Date: Wed, 17 Apr 2019 16:06:35 -0400 Subject: [PATCH 042/270] deps: parseurl@~1.3.3 --- History.md | 1 + package.json | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/History.md b/History.md index f8a5c0c0e10..e1f238bb90a 100644 --- a/History.md +++ b/History.md @@ -5,6 +5,7 @@ unreleased * Improve error message for `null`/`undefined` to `res.status` * Support multiple hosts in `X-Forwarded-Host` * deps: content-disposition@0.5.3 + * deps: parseurl@~1.3.3 * deps: proxy-addr@~2.0.5 - deps: ipaddr.js@1.9.0 diff --git a/package.json b/package.json index 92102c2a76f..e548b609272 100644 --- a/package.json +++ b/package.json @@ -44,7 +44,7 @@ "merge-descriptors": "1.0.1", "methods": "~1.1.2", "on-finished": "~2.3.0", - "parseurl": "~1.3.2", + "parseurl": "~1.3.3", "path-to-regexp": "0.1.7", "proxy-addr": "~2.0.5", "qs": "6.5.2", From b02d3a1744db80a1ad6951f55f4cb6b996db4b53 Mon Sep 17 00:00:00 2001 From: James George Date: Thu, 27 Dec 2018 12:59:51 +0530 Subject: [PATCH 043/270] docs: add link to contributing guide closes #3846 --- Readme.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/Readme.md b/Readme.md index b25b240c7da..81d8d91615e 100644 --- a/Readme.md +++ b/Readme.md @@ -127,6 +127,10 @@ $ npm install $ npm test ``` +## Contributing + +[Contributing Guide](Contributing.md) + ## People The original author of Express is [TJ Holowaychuk](https://github.com/tj) From 7eacdcef190990f2e5a199bb1140322c687e65d7 Mon Sep 17 00:00:00 2001 From: Douglas Christopher Wilson Date: Mon, 22 Apr 2019 13:40:23 -0400 Subject: [PATCH 044/270] deps: setprototypeof@1.1.1 --- History.md | 1 + package.json | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/History.md b/History.md index e1f238bb90a..4f9dcbe96ff 100644 --- a/History.md +++ b/History.md @@ -8,6 +8,7 @@ unreleased * deps: parseurl@~1.3.3 * deps: proxy-addr@~2.0.5 - deps: ipaddr.js@1.9.0 + * deps: setprototypeof@1.1.1 4.16.4 / 2018-10-10 =================== diff --git a/package.json b/package.json index e548b609272..719d689137c 100644 --- a/package.json +++ b/package.json @@ -52,7 +52,7 @@ "safe-buffer": "5.1.2", "send": "0.16.2", "serve-static": "1.13.2", - "setprototypeof": "1.1.0", + "setprototypeof": "1.1.1", "statuses": "~1.4.0", "type-is": "~1.6.16", "utils-merge": "1.0.1", From 9afa1cfc85171dfd8b3595e7b25b7be783c79ae8 Mon Sep 17 00:00:00 2001 From: Douglas Christopher Wilson Date: Tue, 30 Apr 2019 22:17:03 -0400 Subject: [PATCH 045/270] deps: statuses@~1.5.0 --- History.md | 2 ++ package.json | 2 +- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/History.md b/History.md index 4f9dcbe96ff..f0001629d88 100644 --- a/History.md +++ b/History.md @@ -9,6 +9,8 @@ unreleased * deps: proxy-addr@~2.0.5 - deps: ipaddr.js@1.9.0 * deps: setprototypeof@1.1.1 + * deps: statuses@~1.5.0 + - Add `103 Early Hints` 4.16.4 / 2018-10-10 =================== diff --git a/package.json b/package.json index 719d689137c..3834b1f1d2f 100644 --- a/package.json +++ b/package.json @@ -53,7 +53,7 @@ "send": "0.16.2", "serve-static": "1.13.2", "setprototypeof": "1.1.1", - "statuses": "~1.4.0", + "statuses": "~1.5.0", "type-is": "~1.6.16", "utils-merge": "1.0.1", "vary": "~1.1.2" From 40dbfa2de21588d23a8e8e8d43dae5664f0267af Mon Sep 17 00:00:00 2001 From: Douglas Christopher Wilson Date: Tue, 30 Apr 2019 22:24:35 -0400 Subject: [PATCH 046/270] deps: accepts@~1.3.7 --- History.md | 1 + package.json | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/History.md b/History.md index f0001629d88..850f4333cff 100644 --- a/History.md +++ b/History.md @@ -4,6 +4,7 @@ unreleased * Improve error message for non-strings to `res.sendFile` * Improve error message for `null`/`undefined` to `res.status` * Support multiple hosts in `X-Forwarded-Host` + * deps: accepts@~1.3.7 * deps: content-disposition@0.5.3 * deps: parseurl@~1.3.3 * deps: proxy-addr@~2.0.5 diff --git a/package.json b/package.json index 3834b1f1d2f..ee093cc1acb 100644 --- a/package.json +++ b/package.json @@ -27,7 +27,7 @@ "api" ], "dependencies": { - "accepts": "~1.3.5", + "accepts": "~1.3.7", "array-flatten": "1.1.1", "body-parser": "1.18.3", "content-disposition": "0.5.3", From 6d9dd2da49c8d5fce9fccdd9d8257004040a19a7 Mon Sep 17 00:00:00 2001 From: Douglas Christopher Wilson Date: Tue, 30 Apr 2019 22:48:56 -0400 Subject: [PATCH 047/270] deps: type-is@~1.6.18 --- History.md | 3 +++ package.json | 2 +- 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/History.md b/History.md index 850f4333cff..6a7aab401c6 100644 --- a/History.md +++ b/History.md @@ -12,6 +12,9 @@ unreleased * deps: setprototypeof@1.1.1 * deps: statuses@~1.5.0 - Add `103 Early Hints` + * deps: type-is@~1.6.18 + - deps: mime-types@~2.1.24 + - perf: prevent internal `throw` on invalid type 4.16.4 / 2018-10-10 =================== diff --git a/package.json b/package.json index ee093cc1acb..efb712f81fd 100644 --- a/package.json +++ b/package.json @@ -54,7 +54,7 @@ "serve-static": "1.13.2", "setprototypeof": "1.1.1", "statuses": "~1.5.0", - "type-is": "~1.6.16", + "type-is": "~1.6.18", "utils-merge": "1.0.1", "vary": "~1.1.2" }, From 32f5293afa2edb7dd9052922dda3ebdd9eab658d Mon Sep 17 00:00:00 2001 From: Douglas Christopher Wilson Date: Tue, 30 Apr 2019 23:06:50 -0400 Subject: [PATCH 048/270] deps: qs@6.7.0 --- History.md | 2 ++ package.json | 2 +- test/req.query.js | 4 ++-- 3 files changed, 5 insertions(+), 3 deletions(-) diff --git a/History.md b/History.md index 6a7aab401c6..5051207e8ac 100644 --- a/History.md +++ b/History.md @@ -9,6 +9,8 @@ unreleased * deps: parseurl@~1.3.3 * deps: proxy-addr@~2.0.5 - deps: ipaddr.js@1.9.0 + * deps: qs@6.7.0 + - Fix parsing array brackets after index * deps: setprototypeof@1.1.1 * deps: statuses@~1.5.0 - Add `103 Early Hints` diff --git a/package.json b/package.json index efb712f81fd..9730acccbb4 100644 --- a/package.json +++ b/package.json @@ -47,7 +47,7 @@ "parseurl": "~1.3.3", "path-to-regexp": "0.1.7", "proxy-addr": "~2.0.5", - "qs": "6.5.2", + "qs": "6.7.0", "range-parser": "~1.2.0", "safe-buffer": "5.1.2", "send": "0.16.2", diff --git a/test/req.query.js b/test/req.query.js index 7819420ce01..0e810b8ef91 100644 --- a/test/req.query.js +++ b/test/req.query.js @@ -25,8 +25,8 @@ describe('req', function(){ var app = createApp('extended'); request(app) - .get('/?user[name]=tj') - .expect(200, '{"user":{"name":"tj"}}', done); + .get('/?foo[0][bar]=baz&foo[0][fizz]=buzz&foo[]=done!') + .expect(200, '{"foo":[{"bar":"baz","fizz":"buzz"},"done!"]}', done); }); it('should parse parameters with dots', function (done) { From 2f782d8478948124a1c96fe04de259385163100f Mon Sep 17 00:00:00 2001 From: Douglas Christopher Wilson Date: Tue, 30 Apr 2019 23:31:32 -0400 Subject: [PATCH 049/270] deps: body-parser@1.19.0 --- History.md | 10 ++++++++++ package.json | 2 +- 2 files changed, 11 insertions(+), 1 deletion(-) diff --git a/History.md b/History.md index 5051207e8ac..3c2b59a6e22 100644 --- a/History.md +++ b/History.md @@ -5,6 +5,16 @@ unreleased * Improve error message for `null`/`undefined` to `res.status` * Support multiple hosts in `X-Forwarded-Host` * deps: accepts@~1.3.7 + * deps: body-parser@1.19.0 + - Add encoding MIK + - Add petabyte (`pb`) support + - Fix parsing array brackets after index + - deps: bytes@3.1.0 + - deps: http-errors@1.7.2 + - deps: iconv-lite@0.4.24 + - deps: qs@6.7.0 + - deps: raw-body@2.4.0 + - deps: type-is@~1.6.17 * deps: content-disposition@0.5.3 * deps: parseurl@~1.3.3 * deps: proxy-addr@~2.0.5 diff --git a/package.json b/package.json index 9730acccbb4..b443c34c82e 100644 --- a/package.json +++ b/package.json @@ -29,7 +29,7 @@ "dependencies": { "accepts": "~1.3.7", "array-flatten": "1.1.1", - "body-parser": "1.18.3", + "body-parser": "1.19.0", "content-disposition": "0.5.3", "content-type": "~1.0.4", "cookie": "0.3.1", From 955f2a5f78c75cd58f8c4517725a14dd3ee199a4 Mon Sep 17 00:00:00 2001 From: Douglas Christopher Wilson Date: Wed, 1 May 2019 22:59:42 -0400 Subject: [PATCH 050/270] tests: add express.json test suite --- test/exports.js | 6 + test/express.json.js | 664 +++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 670 insertions(+) create mode 100644 test/express.json.js diff --git a/test/exports.js b/test/exports.js index 2a80eedbbe8..bc2bb410fce 100644 --- a/test/exports.js +++ b/test/exports.js @@ -1,4 +1,5 @@ +var assert = require('assert') var express = require('../'); var request = require('supertest'); var should = require('should'); @@ -8,6 +9,11 @@ describe('exports', function(){ express.Router.should.be.a.Function() }) + it('should expose json middleware', function () { + assert.equal(typeof express.json, 'function') + assert.equal(express.json.length, 1) + }) + it('should expose the application prototype', function(){ express.application.set.should.be.a.Function() }) diff --git a/test/express.json.js b/test/express.json.js new file mode 100644 index 00000000000..907fa0cfeb8 --- /dev/null +++ b/test/express.json.js @@ -0,0 +1,664 @@ + +var assert = require('assert') +var Buffer = require('safe-buffer').Buffer +var express = require('..') +var request = require('supertest') + +describe('express.json()', function () { + it('should parse JSON', function (done) { + request(createApp()) + .post('/') + .set('Content-Type', 'application/json') + .send('{"user":"tobi"}') + .expect(200, '{"user":"tobi"}', done) + }) + + it('should handle Content-Length: 0', function (done) { + request(createApp()) + .post('/') + .set('Content-Type', 'application/json') + .set('Content-Length', '0') + .expect(200, '{}', done) + }) + + it('should handle empty message-body', function (done) { + request(createApp()) + .post('/') + .set('Content-Type', 'application/json') + .set('Transfer-Encoding', 'chunked') + .expect(200, '{}', done) + }) + + it('should handle no message-body', function (done) { + request(createApp()) + .post('/') + .set('Content-Type', 'application/json') + .unset('Transfer-Encoding') + .expect(200, '{}', done) + }) + + it('should 400 when invalid content-length', function (done) { + var app = express() + + app.use(function (req, res, next) { + req.headers['content-length'] = '20' // bad length + next() + }) + + app.use(express.json()) + + app.post('/', function (req, res) { + res.json(req.body) + }) + + request(app) + .post('/') + .set('Content-Type', 'application/json') + .send('{"str":') + .expect(400, /content length/, done) + }) + + it('should handle duplicated middleware', function (done) { + var app = express() + + app.use(express.json()) + app.use(express.json()) + + app.post('/', function (req, res) { + res.json(req.body) + }) + + request(app) + .post('/') + .set('Content-Type', 'application/json') + .send('{"user":"tobi"}') + .expect(200, '{"user":"tobi"}', done) + }) + + describe('when JSON is invalid', function () { + before(function () { + this.app = createApp() + }) + + it('should 400 for bad token', function (done) { + request(this.app) + .post('/') + .set('Content-Type', 'application/json') + .send('{:') + .expect(400, parseError('{:'), done) + }) + + it('should 400 for incomplete', function (done) { + request(this.app) + .post('/') + .set('Content-Type', 'application/json') + .send('{"user"') + .expect(400, parseError('{"user"'), done) + }) + + it('should error with type = "entity.parse.failed"', function (done) { + request(this.app) + .post('/') + .set('Content-Type', 'application/json') + .set('X-Error-Property', 'type') + .send(' {"user"') + .expect(400, 'entity.parse.failed', done) + }) + + it('should include original body on error object', function (done) { + request(this.app) + .post('/') + .set('Content-Type', 'application/json') + .set('X-Error-Property', 'body') + .send(' {"user"') + .expect(400, ' {"user"', done) + }) + }) + + describe('with limit option', function () { + it('should 413 when over limit with Content-Length', function (done) { + var buf = Buffer.alloc(1024, '.') + request(createApp({ limit: '1kb' })) + .post('/') + .set('Content-Type', 'application/json') + .set('Content-Length', '1034') + .send(JSON.stringify({ str: buf.toString() })) + .expect(413, done) + }) + + it('should error with type = "entity.too.large"', function (done) { + var buf = Buffer.alloc(1024, '.') + request(createApp({ limit: '1kb' })) + .post('/') + .set('Content-Type', 'application/json') + .set('Content-Length', '1034') + .set('X-Error-Property', 'type') + .send(JSON.stringify({ str: buf.toString() })) + .expect(413, 'entity.too.large', done) + }) + + it('should 413 when over limit with chunked encoding', function (done) { + var buf = Buffer.alloc(1024, '.') + var server = createApp({ limit: '1kb' }) + var test = request(server).post('/') + test.set('Content-Type', 'application/json') + test.set('Transfer-Encoding', 'chunked') + test.write('{"str":') + test.write('"' + buf.toString() + '"}') + test.expect(413, done) + }) + + it('should accept number of bytes', function (done) { + var buf = Buffer.alloc(1024, '.') + request(createApp({ limit: 1024 })) + .post('/') + .set('Content-Type', 'application/json') + .send(JSON.stringify({ str: buf.toString() })) + .expect(413, done) + }) + + it('should not change when options altered', function (done) { + var buf = Buffer.alloc(1024, '.') + var options = { limit: '1kb' } + var server = createApp(options) + + options.limit = '100kb' + + request(server) + .post('/') + .set('Content-Type', 'application/json') + .send(JSON.stringify({ str: buf.toString() })) + .expect(413, done) + }) + + it('should not hang response', function (done) { + var buf = Buffer.alloc(10240, '.') + var server = createApp({ limit: '8kb' }) + var test = request(server).post('/') + test.set('Content-Type', 'application/json') + test.write(buf) + test.write(buf) + test.write(buf) + test.expect(413, done) + }) + }) + + describe('with inflate option', function () { + describe('when false', function () { + before(function () { + this.app = createApp({ inflate: false }) + }) + + it('should not accept content-encoding', function (done) { + var test = request(this.app).post('/') + test.set('Content-Encoding', 'gzip') + test.set('Content-Type', 'application/json') + test.write(Buffer.from('1f8b080000000000000bab56ca4bcc4d55b2527ab16e97522d00515be1cc0e000000', 'hex')) + test.expect(415, 'content encoding unsupported', done) + }) + }) + + describe('when true', function () { + before(function () { + this.app = createApp({ inflate: true }) + }) + + it('should accept content-encoding', function (done) { + var test = request(this.app).post('/') + test.set('Content-Encoding', 'gzip') + test.set('Content-Type', 'application/json') + test.write(Buffer.from('1f8b080000000000000bab56ca4bcc4d55b2527ab16e97522d00515be1cc0e000000', 'hex')) + test.expect(200, '{"name":"论"}', done) + }) + }) + }) + + describe('with strict option', function () { + describe('when undefined', function () { + before(function () { + this.app = createApp() + }) + + it('should 400 on primitives', function (done) { + request(this.app) + .post('/') + .set('Content-Type', 'application/json') + .send('true') + .expect(400, parseError('#rue').replace('#', 't'), done) + }) + }) + + describe('when false', function () { + before(function () { + this.app = createApp({ strict: false }) + }) + + it('should parse primitives', function (done) { + request(this.app) + .post('/') + .set('Content-Type', 'application/json') + .send('true') + .expect(200, 'true', done) + }) + }) + + describe('when true', function () { + before(function () { + this.app = createApp({ strict: true }) + }) + + it('should not parse primitives', function (done) { + request(this.app) + .post('/') + .set('Content-Type', 'application/json') + .send('true') + .expect(400, parseError('#rue').replace('#', 't'), done) + }) + + it('should not parse primitives with leading whitespaces', function (done) { + request(this.app) + .post('/') + .set('Content-Type', 'application/json') + .send(' true') + .expect(400, parseError(' #rue').replace('#', 't'), done) + }) + + it('should allow leading whitespaces in JSON', function (done) { + request(this.app) + .post('/') + .set('Content-Type', 'application/json') + .send(' { "user": "tobi" }') + .expect(200, '{"user":"tobi"}', done) + }) + + it('should error with type = "entity.parse.failed"', function (done) { + request(this.app) + .post('/') + .set('Content-Type', 'application/json') + .set('X-Error-Property', 'type') + .send('true') + .expect(400, 'entity.parse.failed', done) + }) + + it('should include correct message in stack trace', function (done) { + request(this.app) + .post('/') + .set('Content-Type', 'application/json') + .set('X-Error-Property', 'stack') + .send('true') + .expect(400) + .expect(shouldContainInBody(parseError('#rue').replace('#', 't'))) + .end(done) + }) + }) + }) + + describe('with type option', function () { + describe('when "application/vnd.api+json"', function () { + before(function () { + this.app = createApp({ type: 'application/vnd.api+json' }) + }) + + it('should parse JSON for custom type', function (done) { + request(this.app) + .post('/') + .set('Content-Type', 'application/vnd.api+json') + .send('{"user":"tobi"}') + .expect(200, '{"user":"tobi"}', done) + }) + + it('should ignore standard type', function (done) { + request(this.app) + .post('/') + .set('Content-Type', 'application/json') + .send('{"user":"tobi"}') + .expect(200, '{}', done) + }) + }) + + describe('when ["application/json", "application/vnd.api+json"]', function () { + before(function () { + this.app = createApp({ + type: ['application/json', 'application/vnd.api+json'] + }) + }) + + it('should parse JSON for "application/json"', function (done) { + request(this.app) + .post('/') + .set('Content-Type', 'application/json') + .send('{"user":"tobi"}') + .expect(200, '{"user":"tobi"}', done) + }) + + it('should parse JSON for "application/vnd.api+json"', function (done) { + request(this.app) + .post('/') + .set('Content-Type', 'application/vnd.api+json') + .send('{"user":"tobi"}') + .expect(200, '{"user":"tobi"}', done) + }) + + it('should ignore "application/x-json"', function (done) { + request(this.app) + .post('/') + .set('Content-Type', 'application/x-json') + .send('{"user":"tobi"}') + .expect(200, '{}', done) + }) + }) + + describe('when a function', function () { + it('should parse when truthy value returned', function (done) { + var app = createApp({ type: accept }) + + function accept (req) { + return req.headers['content-type'] === 'application/vnd.api+json' + } + + request(app) + .post('/') + .set('Content-Type', 'application/vnd.api+json') + .send('{"user":"tobi"}') + .expect(200, '{"user":"tobi"}', done) + }) + + it('should work without content-type', function (done) { + var app = createApp({ type: accept }) + + function accept (req) { + return true + } + + var test = request(app).post('/') + test.write('{"user":"tobi"}') + test.expect(200, '{"user":"tobi"}', done) + }) + + it('should not invoke without a body', function (done) { + var app = createApp({ type: accept }) + + function accept (req) { + throw new Error('oops!') + } + + request(app) + .get('/') + .expect(404, done) + }) + }) + }) + + describe('with verify option', function () { + it('should assert value if function', function () { + assert.throws(createApp.bind(null, { verify: 'lol' }), + /TypeError: option verify must be function/) + }) + + it('should error from verify', function (done) { + var app = createApp({ verify: function (req, res, buf) { + if (buf[0] === 0x5b) throw new Error('no arrays') + } }) + + request(app) + .post('/') + .set('Content-Type', 'application/json') + .send('["tobi"]') + .expect(403, 'no arrays', done) + }) + + it('should error with type = "entity.verify.failed"', function (done) { + var app = createApp({ verify: function (req, res, buf) { + if (buf[0] === 0x5b) throw new Error('no arrays') + } }) + + request(app) + .post('/') + .set('Content-Type', 'application/json') + .set('X-Error-Property', 'type') + .send('["tobi"]') + .expect(403, 'entity.verify.failed', done) + }) + + it('should allow custom codes', function (done) { + var app = createApp({ verify: function (req, res, buf) { + if (buf[0] !== 0x5b) return + var err = new Error('no arrays') + err.status = 400 + throw err + } }) + + request(app) + .post('/') + .set('Content-Type', 'application/json') + .send('["tobi"]') + .expect(400, 'no arrays', done) + }) + + it('should allow custom type', function (done) { + var app = createApp({ verify: function (req, res, buf) { + if (buf[0] !== 0x5b) return + var err = new Error('no arrays') + err.type = 'foo.bar' + throw err + } }) + + request(app) + .post('/') + .set('Content-Type', 'application/json') + .set('X-Error-Property', 'type') + .send('["tobi"]') + .expect(403, 'foo.bar', done) + }) + + it('should include original body on error object', function (done) { + var app = createApp({ verify: function (req, res, buf) { + if (buf[0] === 0x5b) throw new Error('no arrays') + } }) + + request(app) + .post('/') + .set('Content-Type', 'application/json') + .set('X-Error-Property', 'body') + .send('["tobi"]') + .expect(403, '["tobi"]', done) + }) + + it('should allow pass-through', function (done) { + var app = createApp({ verify: function (req, res, buf) { + if (buf[0] === 0x5b) throw new Error('no arrays') + } }) + + request(app) + .post('/') + .set('Content-Type', 'application/json') + .send('{"user":"tobi"}') + .expect(200, '{"user":"tobi"}', done) + }) + + it('should work with different charsets', function (done) { + var app = createApp({ verify: function (req, res, buf) { + if (buf[0] === 0x5b) throw new Error('no arrays') + } }) + + var test = request(app).post('/') + test.set('Content-Type', 'application/json; charset=utf-16') + test.write(Buffer.from('feff007b0022006e0061006d00650022003a00228bba0022007d', 'hex')) + test.expect(200, '{"name":"论"}', done) + }) + + it('should 415 on unknown charset prior to verify', function (done) { + var app = createApp({ verify: function (req, res, buf) { + throw new Error('unexpected verify call') + } }) + + var test = request(app).post('/') + test.set('Content-Type', 'application/json; charset=x-bogus') + test.write(Buffer.from('00000000', 'hex')) + test.expect(415, 'unsupported charset "X-BOGUS"', done) + }) + }) + + describe('charset', function () { + before(function () { + this.app = createApp() + }) + + it('should parse utf-8', function (done) { + var test = request(this.app).post('/') + test.set('Content-Type', 'application/json; charset=utf-8') + test.write(Buffer.from('7b226e616d65223a22e8aeba227d', 'hex')) + test.expect(200, '{"name":"论"}', done) + }) + + it('should parse utf-16', function (done) { + var test = request(this.app).post('/') + test.set('Content-Type', 'application/json; charset=utf-16') + test.write(Buffer.from('feff007b0022006e0061006d00650022003a00228bba0022007d', 'hex')) + test.expect(200, '{"name":"论"}', done) + }) + + it('should parse when content-length != char length', function (done) { + var test = request(this.app).post('/') + test.set('Content-Type', 'application/json; charset=utf-8') + test.set('Content-Length', '13') + test.write(Buffer.from('7b2274657374223a22c3a5227d', 'hex')) + test.expect(200, '{"test":"å"}', done) + }) + + it('should default to utf-8', function (done) { + var test = request(this.app).post('/') + test.set('Content-Type', 'application/json') + test.write(Buffer.from('7b226e616d65223a22e8aeba227d', 'hex')) + test.expect(200, '{"name":"论"}', done) + }) + + it('should fail on unknown charset', function (done) { + var test = request(this.app).post('/') + test.set('Content-Type', 'application/json; charset=koi8-r') + test.write(Buffer.from('7b226e616d65223a22cec5d4227d', 'hex')) + test.expect(415, 'unsupported charset "KOI8-R"', done) + }) + + it('should error with type = "charset.unsupported"', function (done) { + var test = request(this.app).post('/') + test.set('Content-Type', 'application/json; charset=koi8-r') + test.set('X-Error-Property', 'type') + test.write(Buffer.from('7b226e616d65223a22cec5d4227d', 'hex')) + test.expect(415, 'charset.unsupported', done) + }) + }) + + describe('encoding', function () { + before(function () { + this.app = createApp({ limit: '1kb' }) + }) + + it('should parse without encoding', function (done) { + var test = request(this.app).post('/') + test.set('Content-Type', 'application/json') + test.write(Buffer.from('7b226e616d65223a22e8aeba227d', 'hex')) + test.expect(200, '{"name":"论"}', done) + }) + + it('should support identity encoding', function (done) { + var test = request(this.app).post('/') + test.set('Content-Encoding', 'identity') + test.set('Content-Type', 'application/json') + test.write(Buffer.from('7b226e616d65223a22e8aeba227d', 'hex')) + test.expect(200, '{"name":"论"}', done) + }) + + it('should support gzip encoding', function (done) { + var test = request(this.app).post('/') + test.set('Content-Encoding', 'gzip') + test.set('Content-Type', 'application/json') + test.write(Buffer.from('1f8b080000000000000bab56ca4bcc4d55b2527ab16e97522d00515be1cc0e000000', 'hex')) + test.expect(200, '{"name":"论"}', done) + }) + + it('should support deflate encoding', function (done) { + var test = request(this.app).post('/') + test.set('Content-Encoding', 'deflate') + test.set('Content-Type', 'application/json') + test.write(Buffer.from('789cab56ca4bcc4d55b2527ab16e97522d00274505ac', 'hex')) + test.expect(200, '{"name":"论"}', done) + }) + + it('should be case-insensitive', function (done) { + var test = request(this.app).post('/') + test.set('Content-Encoding', 'GZIP') + test.set('Content-Type', 'application/json') + test.write(Buffer.from('1f8b080000000000000bab56ca4bcc4d55b2527ab16e97522d00515be1cc0e000000', 'hex')) + test.expect(200, '{"name":"论"}', done) + }) + + it('should 415 on unknown encoding', function (done) { + var test = request(this.app).post('/') + test.set('Content-Encoding', 'nulls') + test.set('Content-Type', 'application/json') + test.write(Buffer.from('000000000000', 'hex')) + test.expect(415, 'unsupported content encoding "nulls"', done) + }) + + it('should error with type = "encoding.unsupported"', function (done) { + var test = request(this.app).post('/') + test.set('Content-Encoding', 'nulls') + test.set('Content-Type', 'application/json') + test.set('X-Error-Property', 'type') + test.write(Buffer.from('000000000000', 'hex')) + test.expect(415, 'encoding.unsupported', done) + }) + + it('should 400 on malformed encoding', function (done) { + var test = request(this.app).post('/') + test.set('Content-Encoding', 'gzip') + test.set('Content-Type', 'application/json') + test.write(Buffer.from('1f8b080000000000000bab56cc4d55b2527ab16e97522d00515be1cc0e000000', 'hex')) + test.expect(400, done) + }) + + it('should 413 when inflated value exceeds limit', function (done) { + // gzip'd data exceeds 1kb, but deflated below 1kb + var test = request(this.app).post('/') + test.set('Content-Encoding', 'gzip') + test.set('Content-Type', 'application/json') + test.write(Buffer.from('1f8b080000000000000bedc1010d000000c2a0f74f6d0f071400000000000000', 'hex')) + test.write(Buffer.from('0000000000000000000000000000000000000000000000000000000000000000', 'hex')) + test.write(Buffer.from('0000000000000000004f0625b3b71650c30000', 'hex')) + test.expect(413, done) + }) + }) +}) + +function createApp (options) { + var app = express() + + app.use(express.json(options)) + + app.use(function (err, req, res, next) { + res.status(err.status || 500) + res.send(String(err[req.headers['x-error-property'] || 'message'])) + }) + + app.post('/', function (req, res) { + res.json(req.body) + }) + + return app +} + +function parseError (str) { + try { + JSON.parse(str); throw new SyntaxError('strict violation') + } catch (e) { + return e.message + } +} + +function shouldContainInBody (str) { + return function (res) { + assert.ok(res.text.indexOf(str) !== -1, + 'expected \'' + res.text + '\' to contain \'' + str + '\'') + } +} From 8b71f39516135f8b729de3456f3ae7f6d33442a1 Mon Sep 17 00:00:00 2001 From: Douglas Christopher Wilson Date: Wed, 1 May 2019 23:29:28 -0400 Subject: [PATCH 051/270] tests: add express.urlencoded test suite --- test/exports.js | 5 + test/express.urlencoded.js | 734 +++++++++++++++++++++++++++++++++++++ test/support/env.js | 2 +- 3 files changed, 740 insertions(+), 1 deletion(-) create mode 100644 test/express.urlencoded.js diff --git a/test/exports.js b/test/exports.js index bc2bb410fce..57b3265bd6f 100644 --- a/test/exports.js +++ b/test/exports.js @@ -14,6 +14,11 @@ describe('exports', function(){ assert.equal(express.json.length, 1) }) + it('should expose urlencoded middleware', function () { + assert.equal(typeof express.urlencoded, 'function') + assert.equal(express.urlencoded.length, 1) + }) + it('should expose the application prototype', function(){ express.application.set.should.be.a.Function() }) diff --git a/test/express.urlencoded.js b/test/express.urlencoded.js new file mode 100644 index 00000000000..6011de05f7a --- /dev/null +++ b/test/express.urlencoded.js @@ -0,0 +1,734 @@ + +var assert = require('assert') +var Buffer = require('safe-buffer').Buffer +var express = require('..') +var request = require('supertest') + +describe('express.urlencoded()', function () { + before(function () { + this.app = createApp() + }) + + it('should parse x-www-form-urlencoded', function (done) { + request(this.app) + .post('/') + .set('Content-Type', 'application/x-www-form-urlencoded') + .send('user=tobi') + .expect(200, '{"user":"tobi"}', done) + }) + + it('should 400 when invalid content-length', function (done) { + var app = express() + + app.use(function (req, res, next) { + req.headers['content-length'] = '20' // bad length + next() + }) + + app.use(express.urlencoded()) + + app.post('/', function (req, res) { + res.json(req.body) + }) + + request(app) + .post('/') + .set('Content-Type', 'application/x-www-form-urlencoded') + .send('str=') + .expect(400, /content length/, done) + }) + + it('should handle Content-Length: 0', function (done) { + request(this.app) + .post('/') + .set('Content-Type', 'application/x-www-form-urlencoded') + .set('Content-Length', '0') + .send('') + .expect(200, '{}', done) + }) + + it('should handle empty message-body', function (done) { + request(createApp({ limit: '1kb' })) + .post('/') + .set('Content-Type', 'application/x-www-form-urlencoded') + .set('Transfer-Encoding', 'chunked') + .send('') + .expect(200, '{}', done) + }) + + it('should handle duplicated middleware', function (done) { + var app = express() + + app.use(express.urlencoded()) + app.use(express.urlencoded()) + + app.post('/', function (req, res) { + res.json(req.body) + }) + + request(app) + .post('/') + .set('Content-Type', 'application/x-www-form-urlencoded') + .send('user=tobi') + .expect(200, '{"user":"tobi"}', done) + }) + + it('should parse extended syntax', function (done) { + request(this.app) + .post('/') + .set('Content-Type', 'application/x-www-form-urlencoded') + .send('user[name][first]=Tobi') + .expect(200, '{"user":{"name":{"first":"Tobi"}}}', done) + }) + + describe('with extended option', function () { + describe('when false', function () { + before(function () { + this.app = createApp({ extended: false }) + }) + + it('should not parse extended syntax', function (done) { + request(this.app) + .post('/') + .set('Content-Type', 'application/x-www-form-urlencoded') + .send('user[name][first]=Tobi') + .expect(200, '{"user[name][first]":"Tobi"}', done) + }) + + it('should parse multiple key instances', function (done) { + request(this.app) + .post('/') + .set('Content-Type', 'application/x-www-form-urlencoded') + .send('user=Tobi&user=Loki') + .expect(200, '{"user":["Tobi","Loki"]}', done) + }) + }) + + describe('when true', function () { + before(function () { + this.app = createApp({ extended: true }) + }) + + it('should parse multiple key instances', function (done) { + request(this.app) + .post('/') + .set('Content-Type', 'application/x-www-form-urlencoded') + .send('user=Tobi&user=Loki') + .expect(200, '{"user":["Tobi","Loki"]}', done) + }) + + it('should parse extended syntax', function (done) { + request(this.app) + .post('/') + .set('Content-Type', 'application/x-www-form-urlencoded') + .send('user[name][first]=Tobi') + .expect(200, '{"user":{"name":{"first":"Tobi"}}}', done) + }) + + it('should parse parameters with dots', function (done) { + request(this.app) + .post('/') + .set('Content-Type', 'application/x-www-form-urlencoded') + .send('user.name=Tobi') + .expect(200, '{"user.name":"Tobi"}', done) + }) + + it('should parse fully-encoded extended syntax', function (done) { + request(this.app) + .post('/') + .set('Content-Type', 'application/x-www-form-urlencoded') + .send('user%5Bname%5D%5Bfirst%5D=Tobi') + .expect(200, '{"user":{"name":{"first":"Tobi"}}}', done) + }) + + it('should parse array index notation', function (done) { + request(this.app) + .post('/') + .set('Content-Type', 'application/x-www-form-urlencoded') + .send('foo[0]=bar&foo[1]=baz') + .expect(200, '{"foo":["bar","baz"]}', done) + }) + + it('should parse array index notation with large array', function (done) { + var str = 'f[0]=0' + + for (var i = 1; i < 500; i++) { + str += '&f[' + i + ']=' + i.toString(16) + } + + request(this.app) + .post('/') + .set('Content-Type', 'application/x-www-form-urlencoded') + .send(str) + .expect(function (res) { + var obj = JSON.parse(res.text) + assert.strictEqual(Object.keys(obj).length, 1) + assert.strictEqual(Array.isArray(obj.f), true) + assert.strictEqual(obj.f.length, 500) + }) + .expect(200, done) + }) + + it('should parse array of objects syntax', function (done) { + request(this.app) + .post('/') + .set('Content-Type', 'application/x-www-form-urlencoded') + .send('foo[0][bar]=baz&foo[0][fizz]=buzz&foo[]=done!') + .expect(200, '{"foo":[{"bar":"baz","fizz":"buzz"},"done!"]}', done) + }) + + it('should parse deep object', function (done) { + var str = 'foo' + + for (var i = 0; i < 500; i++) { + str += '[p]' + } + + str += '=bar' + + request(this.app) + .post('/') + .set('Content-Type', 'application/x-www-form-urlencoded') + .send(str) + .expect(function (res) { + var obj = JSON.parse(res.text) + assert.strictEqual(Object.keys(obj).length, 1) + assert.strictEqual(typeof obj.foo, 'object') + + var depth = 0 + var ref = obj.foo + while ((ref = ref.p)) { depth++ } + assert.strictEqual(depth, 500) + }) + .expect(200, done) + }) + }) + }) + + describe('with inflate option', function () { + describe('when false', function () { + before(function () { + this.app = createApp({ inflate: false }) + }) + + it('should not accept content-encoding', function (done) { + var test = request(this.app).post('/') + test.set('Content-Encoding', 'gzip') + test.set('Content-Type', 'application/x-www-form-urlencoded') + test.write(Buffer.from('1f8b080000000000000bcb4bcc4db57db16e170099a4bad608000000', 'hex')) + test.expect(415, 'content encoding unsupported', done) + }) + }) + + describe('when true', function () { + before(function () { + this.app = createApp({ inflate: true }) + }) + + it('should accept content-encoding', function (done) { + var test = request(this.app).post('/') + test.set('Content-Encoding', 'gzip') + test.set('Content-Type', 'application/x-www-form-urlencoded') + test.write(Buffer.from('1f8b080000000000000bcb4bcc4db57db16e170099a4bad608000000', 'hex')) + test.expect(200, '{"name":"论"}', done) + }) + }) + }) + + describe('with limit option', function () { + it('should 413 when over limit with Content-Length', function (done) { + var buf = Buffer.alloc(1024, '.') + request(createApp({ limit: '1kb' })) + .post('/') + .set('Content-Type', 'application/x-www-form-urlencoded') + .set('Content-Length', '1028') + .send('str=' + buf.toString()) + .expect(413, done) + }) + + it('should 413 when over limit with chunked encoding', function (done) { + var buf = Buffer.alloc(1024, '.') + var app = createApp({ limit: '1kb' }) + var test = request(app).post('/') + test.set('Content-Type', 'application/x-www-form-urlencoded') + test.set('Transfer-Encoding', 'chunked') + test.write('str=') + test.write(buf.toString()) + test.expect(413, done) + }) + + it('should accept number of bytes', function (done) { + var buf = Buffer.alloc(1024, '.') + request(createApp({ limit: 1024 })) + .post('/') + .set('Content-Type', 'application/x-www-form-urlencoded') + .send('str=' + buf.toString()) + .expect(413, done) + }) + + it('should not change when options altered', function (done) { + var buf = Buffer.alloc(1024, '.') + var options = { limit: '1kb' } + var app = createApp(options) + + options.limit = '100kb' + + request(app) + .post('/') + .set('Content-Type', 'application/x-www-form-urlencoded') + .send('str=' + buf.toString()) + .expect(413, done) + }) + + it('should not hang response', function (done) { + var buf = Buffer.alloc(10240, '.') + var app = createApp({ limit: '8kb' }) + var test = request(app).post('/') + test.set('Content-Type', 'application/x-www-form-urlencoded') + test.write(buf) + test.write(buf) + test.write(buf) + test.expect(413, done) + }) + }) + + describe('with parameterLimit option', function () { + describe('with extended: false', function () { + it('should reject 0', function () { + assert.throws(createApp.bind(null, { extended: false, parameterLimit: 0 }), + /TypeError: option parameterLimit must be a positive number/) + }) + + it('should reject string', function () { + assert.throws(createApp.bind(null, { extended: false, parameterLimit: 'beep' }), + /TypeError: option parameterLimit must be a positive number/) + }) + + it('should 413 if over limit', function (done) { + request(createApp({ extended: false, parameterLimit: 10 })) + .post('/') + .set('Content-Type', 'application/x-www-form-urlencoded') + .send(createManyParams(11)) + .expect(413, /too many parameters/, done) + }) + + it('should error with type = "parameters.too.many"', function (done) { + request(createApp({ extended: false, parameterLimit: 10 })) + .post('/') + .set('Content-Type', 'application/x-www-form-urlencoded') + .set('X-Error-Property', 'type') + .send(createManyParams(11)) + .expect(413, 'parameters.too.many', done) + }) + + it('should work when at the limit', function (done) { + request(createApp({ extended: false, parameterLimit: 10 })) + .post('/') + .set('Content-Type', 'application/x-www-form-urlencoded') + .send(createManyParams(10)) + .expect(expectKeyCount(10)) + .expect(200, done) + }) + + it('should work if number is floating point', function (done) { + request(createApp({ extended: false, parameterLimit: 10.1 })) + .post('/') + .set('Content-Type', 'application/x-www-form-urlencoded') + .send(createManyParams(11)) + .expect(413, /too many parameters/, done) + }) + + it('should work with large limit', function (done) { + request(createApp({ extended: false, parameterLimit: 5000 })) + .post('/') + .set('Content-Type', 'application/x-www-form-urlencoded') + .send(createManyParams(5000)) + .expect(expectKeyCount(5000)) + .expect(200, done) + }) + + it('should work with Infinity limit', function (done) { + request(createApp({ extended: false, parameterLimit: Infinity })) + .post('/') + .set('Content-Type', 'application/x-www-form-urlencoded') + .send(createManyParams(10000)) + .expect(expectKeyCount(10000)) + .expect(200, done) + }) + }) + + describe('with extended: true', function () { + it('should reject 0', function () { + assert.throws(createApp.bind(null, { extended: true, parameterLimit: 0 }), + /TypeError: option parameterLimit must be a positive number/) + }) + + it('should reject string', function () { + assert.throws(createApp.bind(null, { extended: true, parameterLimit: 'beep' }), + /TypeError: option parameterLimit must be a positive number/) + }) + + it('should 413 if over limit', function (done) { + request(createApp({ extended: true, parameterLimit: 10 })) + .post('/') + .set('Content-Type', 'application/x-www-form-urlencoded') + .send(createManyParams(11)) + .expect(413, /too many parameters/, done) + }) + + it('should error with type = "parameters.too.many"', function (done) { + request(createApp({ extended: true, parameterLimit: 10 })) + .post('/') + .set('Content-Type', 'application/x-www-form-urlencoded') + .set('X-Error-Property', 'type') + .send(createManyParams(11)) + .expect(413, 'parameters.too.many', done) + }) + + it('should work when at the limit', function (done) { + request(createApp({ extended: true, parameterLimit: 10 })) + .post('/') + .set('Content-Type', 'application/x-www-form-urlencoded') + .send(createManyParams(10)) + .expect(expectKeyCount(10)) + .expect(200, done) + }) + + it('should work if number is floating point', function (done) { + request(createApp({ extended: true, parameterLimit: 10.1 })) + .post('/') + .set('Content-Type', 'application/x-www-form-urlencoded') + .send(createManyParams(11)) + .expect(413, /too many parameters/, done) + }) + + it('should work with large limit', function (done) { + request(createApp({ extended: true, parameterLimit: 5000 })) + .post('/') + .set('Content-Type', 'application/x-www-form-urlencoded') + .send(createManyParams(5000)) + .expect(expectKeyCount(5000)) + .expect(200, done) + }) + + it('should work with Infinity limit', function (done) { + request(createApp({ extended: true, parameterLimit: Infinity })) + .post('/') + .set('Content-Type', 'application/x-www-form-urlencoded') + .send(createManyParams(10000)) + .expect(expectKeyCount(10000)) + .expect(200, done) + }) + }) + }) + + describe('with type option', function () { + describe('when "application/vnd.x-www-form-urlencoded"', function () { + before(function () { + this.app = createApp({ type: 'application/vnd.x-www-form-urlencoded' }) + }) + + it('should parse for custom type', function (done) { + request(this.app) + .post('/') + .set('Content-Type', 'application/vnd.x-www-form-urlencoded') + .send('user=tobi') + .expect(200, '{"user":"tobi"}', done) + }) + + it('should ignore standard type', function (done) { + request(this.app) + .post('/') + .set('Content-Type', 'application/x-www-form-urlencoded') + .send('user=tobi') + .expect(200, '{}', done) + }) + }) + + describe('when ["urlencoded", "application/x-pairs"]', function () { + before(function () { + this.app = createApp({ + type: ['urlencoded', 'application/x-pairs'] + }) + }) + + it('should parse "application/x-www-form-urlencoded"', function (done) { + request(this.app) + .post('/') + .set('Content-Type', 'application/x-www-form-urlencoded') + .send('user=tobi') + .expect(200, '{"user":"tobi"}', done) + }) + + it('should parse "application/x-pairs"', function (done) { + request(this.app) + .post('/') + .set('Content-Type', 'application/x-pairs') + .send('user=tobi') + .expect(200, '{"user":"tobi"}', done) + }) + + it('should ignore application/x-foo', function (done) { + request(this.app) + .post('/') + .set('Content-Type', 'application/x-foo') + .send('user=tobi') + .expect(200, '{}', done) + }) + }) + + describe('when a function', function () { + it('should parse when truthy value returned', function (done) { + var app = createApp({ type: accept }) + + function accept (req) { + return req.headers['content-type'] === 'application/vnd.something' + } + + request(app) + .post('/') + .set('Content-Type', 'application/vnd.something') + .send('user=tobi') + .expect(200, '{"user":"tobi"}', done) + }) + + it('should work without content-type', function (done) { + var app = createApp({ type: accept }) + + function accept (req) { + return true + } + + var test = request(app).post('/') + test.write('user=tobi') + test.expect(200, '{"user":"tobi"}', done) + }) + + it('should not invoke without a body', function (done) { + var app = createApp({ type: accept }) + + function accept (req) { + throw new Error('oops!') + } + + request(app) + .get('/') + .expect(404, done) + }) + }) + }) + + describe('with verify option', function () { + it('should assert value if function', function () { + assert.throws(createApp.bind(null, { verify: 'lol' }), + /TypeError: option verify must be function/) + }) + + it('should error from verify', function (done) { + var app = createApp({ verify: function (req, res, buf) { + if (buf[0] === 0x20) throw new Error('no leading space') + } }) + + request(app) + .post('/') + .set('Content-Type', 'application/x-www-form-urlencoded') + .send(' user=tobi') + .expect(403, 'no leading space', done) + }) + + it('should error with type = "entity.verify.failed"', function (done) { + var app = createApp({ verify: function (req, res, buf) { + if (buf[0] === 0x20) throw new Error('no leading space') + } }) + + request(app) + .post('/') + .set('Content-Type', 'application/x-www-form-urlencoded') + .set('X-Error-Property', 'type') + .send(' user=tobi') + .expect(403, 'entity.verify.failed', done) + }) + + it('should allow custom codes', function (done) { + var app = createApp({ verify: function (req, res, buf) { + if (buf[0] !== 0x20) return + var err = new Error('no leading space') + err.status = 400 + throw err + } }) + + request(app) + .post('/') + .set('Content-Type', 'application/x-www-form-urlencoded') + .send(' user=tobi') + .expect(400, 'no leading space', done) + }) + + it('should allow custom type', function (done) { + var app = createApp({ verify: function (req, res, buf) { + if (buf[0] !== 0x20) return + var err = new Error('no leading space') + err.type = 'foo.bar' + throw err + } }) + + request(app) + .post('/') + .set('Content-Type', 'application/x-www-form-urlencoded') + .set('X-Error-Property', 'type') + .send(' user=tobi') + .expect(403, 'foo.bar', done) + }) + + it('should allow pass-through', function (done) { + var app = createApp({ verify: function (req, res, buf) { + if (buf[0] === 0x5b) throw new Error('no arrays') + } }) + + request(app) + .post('/') + .set('Content-Type', 'application/x-www-form-urlencoded') + .send('user=tobi') + .expect(200, '{"user":"tobi"}', done) + }) + + it('should 415 on unknown charset prior to verify', function (done) { + var app = createApp({ verify: function (req, res, buf) { + throw new Error('unexpected verify call') + } }) + + var test = request(app).post('/') + test.set('Content-Type', 'application/x-www-form-urlencoded; charset=x-bogus') + test.write(Buffer.from('00000000', 'hex')) + test.expect(415, 'unsupported charset "X-BOGUS"', done) + }) + }) + + describe('charset', function () { + before(function () { + this.app = createApp() + }) + + it('should parse utf-8', function (done) { + var test = request(this.app).post('/') + test.set('Content-Type', 'application/x-www-form-urlencoded; charset=utf-8') + test.write(Buffer.from('6e616d653de8aeba', 'hex')) + test.expect(200, '{"name":"论"}', done) + }) + + it('should parse when content-length != char length', function (done) { + var test = request(this.app).post('/') + test.set('Content-Type', 'application/x-www-form-urlencoded; charset=utf-8') + test.set('Content-Length', '7') + test.write(Buffer.from('746573743dc3a5', 'hex')) + test.expect(200, '{"test":"å"}', done) + }) + + it('should default to utf-8', function (done) { + var test = request(this.app).post('/') + test.set('Content-Type', 'application/x-www-form-urlencoded') + test.write(Buffer.from('6e616d653de8aeba', 'hex')) + test.expect(200, '{"name":"论"}', done) + }) + + it('should fail on unknown charset', function (done) { + var test = request(this.app).post('/') + test.set('Content-Type', 'application/x-www-form-urlencoded; charset=koi8-r') + test.write(Buffer.from('6e616d653dcec5d4', 'hex')) + test.expect(415, 'unsupported charset "KOI8-R"', done) + }) + }) + + describe('encoding', function () { + before(function () { + this.app = createApp({ limit: '10kb' }) + }) + + it('should parse without encoding', function (done) { + var test = request(this.app).post('/') + test.set('Content-Type', 'application/x-www-form-urlencoded') + test.write(Buffer.from('6e616d653de8aeba', 'hex')) + test.expect(200, '{"name":"论"}', done) + }) + + it('should support identity encoding', function (done) { + var test = request(this.app).post('/') + test.set('Content-Encoding', 'identity') + test.set('Content-Type', 'application/x-www-form-urlencoded') + test.write(Buffer.from('6e616d653de8aeba', 'hex')) + test.expect(200, '{"name":"论"}', done) + }) + + it('should support gzip encoding', function (done) { + var test = request(this.app).post('/') + test.set('Content-Encoding', 'gzip') + test.set('Content-Type', 'application/x-www-form-urlencoded') + test.write(Buffer.from('1f8b080000000000000bcb4bcc4db57db16e170099a4bad608000000', 'hex')) + test.expect(200, '{"name":"论"}', done) + }) + + it('should support deflate encoding', function (done) { + var test = request(this.app).post('/') + test.set('Content-Encoding', 'deflate') + test.set('Content-Type', 'application/x-www-form-urlencoded') + test.write(Buffer.from('789ccb4bcc4db57db16e17001068042f', 'hex')) + test.expect(200, '{"name":"论"}', done) + }) + + it('should be case-insensitive', function (done) { + var test = request(this.app).post('/') + test.set('Content-Encoding', 'GZIP') + test.set('Content-Type', 'application/x-www-form-urlencoded') + test.write(Buffer.from('1f8b080000000000000bcb4bcc4db57db16e170099a4bad608000000', 'hex')) + test.expect(200, '{"name":"论"}', done) + }) + + it('should fail on unknown encoding', function (done) { + var test = request(this.app).post('/') + test.set('Content-Encoding', 'nulls') + test.set('Content-Type', 'application/x-www-form-urlencoded') + test.write(Buffer.from('000000000000', 'hex')) + test.expect(415, 'unsupported content encoding "nulls"', done) + }) + }) +}) + +function createManyParams (count) { + var str = '' + + if (count === 0) { + return str + } + + str += '0=0' + + for (var i = 1; i < count; i++) { + var n = i.toString(36) + str += '&' + n + '=' + n + } + + return str +} + +function createApp (options) { + var app = express() + + app.use(express.urlencoded(options)) + + app.use(function (err, req, res, next) { + res.status(err.status || 500) + res.send(String(err[req.headers['x-error-property'] || 'message'])) + }) + + app.post('/', function (req, res) { + res.json(req.body) + }) + + return app +} + +function expectKeyCount (count) { + return function (res) { + assert.strictEqual(Object.keys(JSON.parse(res.text)).length, count) + } +} diff --git a/test/support/env.js b/test/support/env.js index 0701f5e334f..000638ceeae 100644 --- a/test/support/env.js +++ b/test/support/env.js @@ -1,3 +1,3 @@ process.env.NODE_ENV = 'test'; -process.env.NO_DEPRECATION = 'express'; +process.env.NO_DEPRECATION = 'body-parser,express'; From 6f7a8301a1828febe0b10af62152558d118b039c Mon Sep 17 00:00:00 2001 From: Douglas Christopher Wilson Date: Thu, 2 May 2019 17:49:29 -0400 Subject: [PATCH 052/270] tests: add express.static test suite --- test/exports.js | 5 + test/express.static.js | 813 +++++++++++++++++++++ test/fixtures/empty.txt | 0 test/fixtures/nums.txt | 1 + test/fixtures/pets/names.txt | 1 + "test/fixtures/snow \342\230\203/.gitkeep" | 0 test/fixtures/todo.html | 1 + test/fixtures/todo.txt | 1 + test/fixtures/users/index.html | 1 + test/fixtures/users/tobi.txt | 1 + test/support/utils.js | 34 + 11 files changed, 858 insertions(+) create mode 100644 test/express.static.js create mode 100644 test/fixtures/empty.txt create mode 100644 test/fixtures/nums.txt create mode 100644 test/fixtures/pets/names.txt create mode 100644 "test/fixtures/snow \342\230\203/.gitkeep" create mode 100644 test/fixtures/todo.html create mode 100644 test/fixtures/todo.txt create mode 100644 test/fixtures/users/index.html create mode 100644 test/fixtures/users/tobi.txt diff --git a/test/exports.js b/test/exports.js index 57b3265bd6f..e5fb6f2a9cf 100644 --- a/test/exports.js +++ b/test/exports.js @@ -14,6 +14,11 @@ describe('exports', function(){ assert.equal(express.json.length, 1) }) + it('should expose static middleware', function () { + assert.equal(typeof express.static, 'function') + assert.equal(express.static.length, 2) + }) + it('should expose urlencoded middleware', function () { assert.equal(typeof express.urlencoded, 'function') assert.equal(express.urlencoded.length, 1) diff --git a/test/express.static.js b/test/express.static.js new file mode 100644 index 00000000000..7c9852243e6 --- /dev/null +++ b/test/express.static.js @@ -0,0 +1,813 @@ + +var assert = require('assert') +var Buffer = require('safe-buffer').Buffer +var express = require('..') +var path = require('path') +var request = require('supertest') +var utils = require('./support/utils') + +var fixtures = path.join(__dirname, '/fixtures') +var relative = path.relative(process.cwd(), fixtures) + +var skipRelative = ~relative.indexOf('..') || path.resolve(relative) === relative + +describe('express.static()', function () { + describe('basic operations', function () { + before(function () { + this.app = createApp() + }) + + it('should require root path', function () { + assert.throws(express.static.bind(), /root path required/) + }) + + it('should require root path to be string', function () { + assert.throws(express.static.bind(null, 42), /root path.*string/) + }) + + it('should serve static files', function (done) { + request(this.app) + .get('/todo.txt') + .expect(200, '- groceries', done) + }) + + it('should support nesting', function (done) { + request(this.app) + .get('/users/tobi.txt') + .expect(200, 'ferret', done) + }) + + it('should set Content-Type', function (done) { + request(this.app) + .get('/todo.txt') + .expect('Content-Type', 'text/plain; charset=UTF-8') + .expect(200, done) + }) + + it('should set Last-Modified', function (done) { + request(this.app) + .get('/todo.txt') + .expect('Last-Modified', /\d{2} \w{3} \d{4}/) + .expect(200, done) + }) + + it('should default max-age=0', function (done) { + request(this.app) + .get('/todo.txt') + .expect('Cache-Control', 'public, max-age=0') + .expect(200, done) + }) + + it('should support urlencoded pathnames', function (done) { + request(this.app) + .get('/%25%20of%20dogs.txt') + .expect(200, '20%', done) + }) + + it('should not choke on auth-looking URL', function (done) { + request(this.app) + .get('//todo@txt') + .expect(404, 'Not Found', done) + }) + + it('should support index.html', function (done) { + request(this.app) + .get('/users/') + .expect(200) + .expect('Content-Type', /html/) + .expect('

tobi, loki, jane

', done) + }) + + it('should support ../', function (done) { + request(this.app) + .get('/users/../todo.txt') + .expect(200, '- groceries', done) + }) + + it('should support HEAD', function (done) { + request(this.app) + .head('/todo.txt') + .expect(200) + .expect(utils.shouldNotHaveBody()) + .end(done) + }) + + it('should skip POST requests', function (done) { + request(this.app) + .post('/todo.txt') + .expect(404, 'Not Found', done) + }) + + it('should support conditional requests', function (done) { + var app = this.app + + request(app) + .get('/todo.txt') + .end(function (err, res) { + if (err) throw err + request(app) + .get('/todo.txt') + .set('If-None-Match', res.headers.etag) + .expect(304, done) + }) + }) + + it('should support precondition checks', function (done) { + request(this.app) + .get('/todo.txt') + .set('If-Match', '"foo"') + .expect(412, done) + }) + + it('should serve zero-length files', function (done) { + request(this.app) + .get('/empty.txt') + .expect(200, '', done) + }) + + it('should ignore hidden files', function (done) { + request(this.app) + .get('/.name') + .expect(404, 'Not Found', done) + }) + }); + + (skipRelative ? describe.skip : describe)('current dir', function () { + before(function () { + this.app = createApp('.') + }) + + it('should be served with "."', function (done) { + var dest = relative.split(path.sep).join('/') + request(this.app) + .get('/' + dest + '/todo.txt') + .expect(200, '- groceries', done) + }) + }) + + describe('acceptRanges', function () { + describe('when false', function () { + it('should not include Accept-Ranges', function (done) { + request(createApp(fixtures, { 'acceptRanges': false })) + .get('/nums.txt') + .expect(utils.shouldNotHaveHeader('Accept-Ranges')) + .expect(200, '123456789', done) + }) + + it('should ignore Rage request header', function (done) { + request(createApp(fixtures, { 'acceptRanges': false })) + .get('/nums.txt') + .set('Range', 'bytes=0-3') + .expect(utils.shouldNotHaveHeader('Accept-Ranges')) + .expect(utils.shouldNotHaveHeader('Content-Range')) + .expect(200, '123456789', done) + }) + }) + + describe('when true', function () { + it('should include Accept-Ranges', function (done) { + request(createApp(fixtures, { 'acceptRanges': true })) + .get('/nums.txt') + .expect('Accept-Ranges', 'bytes') + .expect(200, '123456789', done) + }) + + it('should obey Rage request header', function (done) { + request(createApp(fixtures, { 'acceptRanges': true })) + .get('/nums.txt') + .set('Range', 'bytes=0-3') + .expect('Accept-Ranges', 'bytes') + .expect('Content-Range', 'bytes 0-3/9') + .expect(206, '1234', done) + }) + }) + }) + + describe('cacheControl', function () { + describe('when false', function () { + it('should not include Cache-Control', function (done) { + request(createApp(fixtures, { 'cacheControl': false })) + .get('/nums.txt') + .expect(utils.shouldNotHaveHeader('Cache-Control')) + .expect(200, '123456789', done) + }) + + it('should ignore maxAge', function (done) { + request(createApp(fixtures, { 'cacheControl': false, 'maxAge': 12000 })) + .get('/nums.txt') + .expect(utils.shouldNotHaveHeader('Cache-Control')) + .expect(200, '123456789', done) + }) + }) + + describe('when true', function () { + it('should include Cache-Control', function (done) { + request(createApp(fixtures, { 'cacheControl': true })) + .get('/nums.txt') + .expect('Cache-Control', 'public, max-age=0') + .expect(200, '123456789', done) + }) + }) + }) + + describe('extensions', function () { + it('should be not be enabled by default', function (done) { + request(createApp(fixtures)) + .get('/todo') + .expect(404, done) + }) + + it('should be configurable', function (done) { + request(createApp(fixtures, { 'extensions': 'txt' })) + .get('/todo') + .expect(200, '- groceries', done) + }) + + it('should support disabling extensions', function (done) { + request(createApp(fixtures, { 'extensions': false })) + .get('/todo') + .expect(404, done) + }) + + it('should support fallbacks', function (done) { + request(createApp(fixtures, { 'extensions': ['htm', 'html', 'txt'] })) + .get('/todo') + .expect(200, '
  • groceries
  • ', done) + }) + + it('should 404 if nothing found', function (done) { + request(createApp(fixtures, { 'extensions': ['htm', 'html', 'txt'] })) + .get('/bob') + .expect(404, done) + }) + }) + + describe('fallthrough', function () { + it('should default to true', function (done) { + request(createApp()) + .get('/does-not-exist') + .expect(404, 'Not Found', done) + }) + + describe('when true', function () { + before(function () { + this.app = createApp(fixtures, { 'fallthrough': true }) + }) + + it('should fall-through when OPTIONS request', function (done) { + request(this.app) + .options('/todo.txt') + .expect(404, 'Not Found', done) + }) + + it('should fall-through when URL malformed', function (done) { + request(this.app) + .get('/%') + .expect(404, 'Not Found', done) + }) + + it('should fall-through when traversing past root', function (done) { + request(this.app) + .get('/users/../../todo.txt') + .expect(404, 'Not Found', done) + }) + + it('should fall-through when URL too long', function (done) { + var app = express() + var root = fixtures + Array(10000).join('/foobar') + + app.use(express.static(root, { 'fallthrough': true })) + app.use(function (req, res, next) { + res.sendStatus(404) + }) + + request(app) + .get('/') + .expect(404, 'Not Found', done) + }) + + describe('with redirect: true', function () { + before(function () { + this.app = createApp(fixtures, { 'fallthrough': true, 'redirect': true }) + }) + + it('should fall-through when directory', function (done) { + request(this.app) + .get('/pets/') + .expect(404, 'Not Found', done) + }) + + it('should redirect when directory without slash', function (done) { + request(this.app) + .get('/pets') + .expect(301, /Redirecting/, done) + }) + }) + + describe('with redirect: false', function () { + before(function () { + this.app = createApp(fixtures, { 'fallthrough': true, 'redirect': false }) + }) + + it('should fall-through when directory', function (done) { + request(this.app) + .get('/pets/') + .expect(404, 'Not Found', done) + }) + + it('should fall-through when directory without slash', function (done) { + request(this.app) + .get('/pets') + .expect(404, 'Not Found', done) + }) + }) + }) + + describe('when false', function () { + before(function () { + this.app = createApp(fixtures, { 'fallthrough': false }) + }) + + it('should 405 when OPTIONS request', function (done) { + request(this.app) + .options('/todo.txt') + .expect('Allow', 'GET, HEAD') + .expect(405, done) + }) + + it('should 400 when URL malformed', function (done) { + request(this.app) + .get('/%') + .expect(400, /BadRequestError/, done) + }) + + it('should 403 when traversing past root', function (done) { + request(this.app) + .get('/users/../../todo.txt') + .expect(403, /ForbiddenError/, done) + }) + + it('should 404 when URL too long', function (done) { + var app = express() + var root = fixtures + Array(10000).join('/foobar') + + app.use(express.static(root, { 'fallthrough': false })) + app.use(function (req, res, next) { + res.sendStatus(404) + }) + + request(app) + .get('/') + .expect(404, /ENAMETOOLONG/, done) + }) + + describe('with redirect: true', function () { + before(function () { + this.app = createApp(fixtures, { 'fallthrough': false, 'redirect': true }) + }) + + it('should 404 when directory', function (done) { + request(this.app) + .get('/pets/') + .expect(404, /NotFoundError|ENOENT/, done) + }) + + it('should redirect when directory without slash', function (done) { + request(this.app) + .get('/pets') + .expect(301, /Redirecting/, done) + }) + }) + + describe('with redirect: false', function () { + before(function () { + this.app = createApp(fixtures, { 'fallthrough': false, 'redirect': false }) + }) + + it('should 404 when directory', function (done) { + request(this.app) + .get('/pets/') + .expect(404, /NotFoundError|ENOENT/, done) + }) + + it('should 404 when directory without slash', function (done) { + request(this.app) + .get('/pets') + .expect(404, /NotFoundError|ENOENT/, done) + }) + }) + }) + }) + + describe('hidden files', function () { + before(function () { + this.app = createApp(fixtures, { 'dotfiles': 'allow' }) + }) + + it('should be served when dotfiles: "allow" is given', function (done) { + request(this.app) + .get('/.name') + .expect(200) + .expect(utils.shouldHaveBody(Buffer.from('tobi'))) + .end(done) + }) + }) + + describe('immutable', function () { + it('should default to false', function (done) { + request(createApp(fixtures)) + .get('/nums.txt') + .expect('Cache-Control', 'public, max-age=0', done) + }) + + it('should set immutable directive in Cache-Control', function (done) { + request(createApp(fixtures, { 'immutable': true, 'maxAge': '1h' })) + .get('/nums.txt') + .expect('Cache-Control', 'public, max-age=3600, immutable', done) + }) + }) + + describe('lastModified', function () { + describe('when false', function () { + it('should not include Last-Modifed', function (done) { + request(createApp(fixtures, { 'lastModified': false })) + .get('/nums.txt') + .expect(utils.shouldNotHaveHeader('Last-Modified')) + .expect(200, '123456789', done) + }) + }) + + describe('when true', function () { + it('should include Last-Modifed', function (done) { + request(createApp(fixtures, { 'lastModified': true })) + .get('/nums.txt') + .expect('Last-Modified', /^\w{3}, \d+ \w+ \d+ \d+:\d+:\d+ \w+$/) + .expect(200, '123456789', done) + }) + }) + }) + + describe('maxAge', function () { + it('should accept string', function (done) { + request(createApp(fixtures, { 'maxAge': '30d' })) + .get('/todo.txt') + .expect('cache-control', 'public, max-age=' + (60 * 60 * 24 * 30)) + .expect(200, done) + }) + + it('should be reasonable when infinite', function (done) { + request(createApp(fixtures, { 'maxAge': Infinity })) + .get('/todo.txt') + .expect('cache-control', 'public, max-age=' + (60 * 60 * 24 * 365)) + .expect(200, done) + }) + }) + + describe('redirect', function () { + before(function () { + this.app = express() + this.app.use(function (req, res, next) { + req.originalUrl = req.url = + req.originalUrl.replace(/\/snow(\/|$)/, '/snow \u2603$1') + next() + }) + this.app.use(express.static(fixtures)) + }) + + it('should redirect directories', function (done) { + request(this.app) + .get('/users') + .expect('Location', '/users/') + .expect(301, done) + }) + + it('should include HTML link', function (done) { + request(this.app) + .get('/users') + .expect('Location', '/users/') + .expect(301, //, done) + }) + + it('should redirect directories with query string', function (done) { + request(this.app) + .get('/users?name=john') + .expect('Location', '/users/?name=john') + .expect(301, done) + }) + + it('should not redirect to protocol-relative locations', function (done) { + request(this.app) + .get('//users') + .expect('Location', '/users/') + .expect(301, done) + }) + + it('should ensure redirect URL is properly encoded', function (done) { + request(this.app) + .get('/snow') + .expect('Location', '/snow%20%E2%98%83/') + .expect('Content-Type', /html/) + .expect(301, />Redirecting to \/snow%20%E2%98%83\/<\/a>groceries \ No newline at end of file diff --git a/test/fixtures/todo.txt b/test/fixtures/todo.txt new file mode 100644 index 00000000000..8c3539d9461 --- /dev/null +++ b/test/fixtures/todo.txt @@ -0,0 +1 @@ +- groceries \ No newline at end of file diff --git a/test/fixtures/users/index.html b/test/fixtures/users/index.html new file mode 100644 index 00000000000..00a2db41f75 --- /dev/null +++ b/test/fixtures/users/index.html @@ -0,0 +1 @@ +

    tobi, loki, jane

    \ No newline at end of file diff --git a/test/fixtures/users/tobi.txt b/test/fixtures/users/tobi.txt new file mode 100644 index 00000000000..9d9529d47d7 --- /dev/null +++ b/test/fixtures/users/tobi.txt @@ -0,0 +1 @@ +ferret \ No newline at end of file diff --git a/test/support/utils.js b/test/support/utils.js index ec6b801bc09..579f042a0c2 100644 --- a/test/support/utils.js +++ b/test/support/utils.js @@ -3,14 +3,48 @@ * Module dependencies. * @private */ + var assert = require('assert'); +var Buffer = require('safe-buffer').Buffer /** * Module exports. * @public */ + +exports.shouldHaveBody = shouldHaveBody +exports.shouldNotHaveBody = shouldNotHaveBody exports.shouldNotHaveHeader = shouldNotHaveHeader; +/** + * Assert that a supertest response has a specific body. + * + * @param {Buffer} buf + * @returns {function} + */ + +function shouldHaveBody (buf) { + return function (res) { + var body = !Buffer.isBuffer(res.body) + ? Buffer.from(res.text) + : res.body + assert.ok(body, 'response has body') + assert.strictEqual(body.toString('hex'), buf.toString('hex')) + } +} + +/** + * Assert that a supertest response does not have a body. + * + * @returns {function} + */ + +function shouldNotHaveBody () { + return function (res) { + assert.ok(res.text === '' || res.text === undefined) + } +} + /** * Assert that a supertest response does not have a header. * From 70a19472f1ec22642ea98baa5f76b5ba656e7235 Mon Sep 17 00:00:00 2001 From: Douglas Christopher Wilson Date: Tue, 7 May 2019 23:05:37 -0400 Subject: [PATCH 053/270] deps: send@0.17.0 --- History.md | 6 ++++++ package.json | 2 +- 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/History.md b/History.md index 3c2b59a6e22..688efb690e9 100644 --- a/History.md +++ b/History.md @@ -21,6 +21,12 @@ unreleased - deps: ipaddr.js@1.9.0 * deps: qs@6.7.0 - Fix parsing array brackets after index + * deps: send@0.17.0 + - deps: http-errors@~1.7.2 + - deps: mime@1.6.0 + - deps: ms@2.1.1 + - deps: statuses@~1.5.0 + - perf: remove redundant `path.normalize` call * deps: setprototypeof@1.1.1 * deps: statuses@~1.5.0 - Add `103 Early Hints` diff --git a/package.json b/package.json index b443c34c82e..53753369f7b 100644 --- a/package.json +++ b/package.json @@ -50,7 +50,7 @@ "qs": "6.7.0", "range-parser": "~1.2.0", "safe-buffer": "5.1.2", - "send": "0.16.2", + "send": "0.17.0", "serve-static": "1.13.2", "setprototypeof": "1.1.1", "statuses": "~1.5.0", From 60aacac1670f01857961fb7d765eb015efb0be5b Mon Sep 17 00:00:00 2001 From: Douglas Christopher Wilson Date: Tue, 7 May 2019 23:42:36 -0400 Subject: [PATCH 054/270] deps: serve-static@1.14.0 closes #3486 --- History.md | 3 +++ package.json | 2 +- 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/History.md b/History.md index 688efb690e9..71db3e8ef7a 100644 --- a/History.md +++ b/History.md @@ -27,6 +27,9 @@ unreleased - deps: ms@2.1.1 - deps: statuses@~1.5.0 - perf: remove redundant `path.normalize` call + * deps: serve-static@1.14.0 + - deps: parseurl@~1.3.3 + - deps: send@0.17.0 * deps: setprototypeof@1.1.1 * deps: statuses@~1.5.0 - Add `103 Early Hints` diff --git a/package.json b/package.json index 53753369f7b..ef83d58d116 100644 --- a/package.json +++ b/package.json @@ -51,7 +51,7 @@ "range-parser": "~1.2.0", "safe-buffer": "5.1.2", "send": "0.17.0", - "serve-static": "1.13.2", + "serve-static": "1.14.0", "setprototypeof": "1.1.1", "statuses": "~1.5.0", "type-is": "~1.6.18", From 0bcdd88dd089c8da7f29e76e8f152a40ca0bcf69 Mon Sep 17 00:00:00 2001 From: Amit Zur Date: Wed, 8 Aug 2018 07:42:00 +0300 Subject: [PATCH 055/270] Add express.raw to parse bodies into Buffer closes #3708 --- History.md | 1 + lib/express.js | 1 + test/exports.js | 5 +++++ 3 files changed, 7 insertions(+) diff --git a/History.md b/History.md index 71db3e8ef7a..35259befeea 100644 --- a/History.md +++ b/History.md @@ -1,6 +1,7 @@ unreleased ========== + * Add `express.raw` to parse bodies into `Buffer` * Improve error message for non-strings to `res.sendFile` * Improve error message for `null`/`undefined` to `res.status` * Support multiple hosts in `X-Forwarded-Host` diff --git a/lib/express.js b/lib/express.js index 594007b5b43..f618ccc125a 100644 --- a/lib/express.js +++ b/lib/express.js @@ -77,6 +77,7 @@ exports.Router = Router; exports.json = bodyParser.json exports.query = require('./middleware/query'); +exports.raw = bodyParser.raw exports.static = require('serve-static'); exports.urlencoded = bodyParser.urlencoded diff --git a/test/exports.js b/test/exports.js index e5fb6f2a9cf..f43df44c34c 100644 --- a/test/exports.js +++ b/test/exports.js @@ -14,6 +14,11 @@ describe('exports', function(){ assert.equal(express.json.length, 1) }) + it('should expose raw middleware', function () { + assert.equal(typeof express.raw, 'function') + assert.equal(express.raw.length, 1) + }) + it('should expose static middleware', function () { assert.equal(typeof express.static, 'function') assert.equal(express.static.length, 2) From 11192bd168c5996efe718664a3f4d8f77dbaa71b Mon Sep 17 00:00:00 2001 From: Douglas Christopher Wilson Date: Wed, 8 May 2019 00:58:08 -0400 Subject: [PATCH 056/270] tests: add express.raw test suite --- test/express.raw.js | 387 ++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 387 insertions(+) create mode 100644 test/express.raw.js diff --git a/test/express.raw.js b/test/express.raw.js new file mode 100644 index 00000000000..571c29ca9bc --- /dev/null +++ b/test/express.raw.js @@ -0,0 +1,387 @@ + +var assert = require('assert') +var Buffer = require('safe-buffer').Buffer +var express = require('..') +var request = require('supertest') + +describe('express.raw()', function () { + before(function () { + this.app = createApp() + }) + + it('should parse application/octet-stream', function (done) { + request(this.app) + .post('/') + .set('Content-Type', 'application/octet-stream') + .send('the user is tobi') + .expect(200, { buf: '746865207573657220697320746f6269' }, done) + }) + + it('should 400 when invalid content-length', function (done) { + var app = express() + + app.use(function (req, res, next) { + req.headers['content-length'] = '20' // bad length + next() + }) + + app.use(express.raw()) + + app.post('/', function (req, res) { + if (Buffer.isBuffer(req.body)) { + res.json({ buf: req.body.toString('hex') }) + } else { + res.json(req.body) + } + }) + + request(app) + .post('/') + .set('Content-Type', 'application/octet-stream') + .send('stuff') + .expect(400, /content length/, done) + }) + + it('should handle Content-Length: 0', function (done) { + request(this.app) + .post('/') + .set('Content-Type', 'application/octet-stream') + .set('Content-Length', '0') + .expect(200, { buf: '' }, done) + }) + + it('should handle empty message-body', function (done) { + request(this.app) + .post('/') + .set('Content-Type', 'application/octet-stream') + .set('Transfer-Encoding', 'chunked') + .send('') + .expect(200, { buf: '' }, done) + }) + + it('should handle duplicated middleware', function (done) { + var app = express() + + app.use(express.raw()) + app.use(express.raw()) + + app.post('/', function (req, res) { + if (Buffer.isBuffer(req.body)) { + res.json({ buf: req.body.toString('hex') }) + } else { + res.json(req.body) + } + }) + + request(app) + .post('/') + .set('Content-Type', 'application/octet-stream') + .send('the user is tobi') + .expect(200, { buf: '746865207573657220697320746f6269' }, done) + }) + + describe('with limit option', function () { + it('should 413 when over limit with Content-Length', function (done) { + var buf = Buffer.alloc(1028, '.') + var app = createApp({ limit: '1kb' }) + var test = request(app).post('/') + test.set('Content-Type', 'application/octet-stream') + test.set('Content-Length', '1028') + test.write(buf) + test.expect(413, done) + }) + + it('should 413 when over limit with chunked encoding', function (done) { + var buf = Buffer.alloc(1028, '.') + var app = createApp({ limit: '1kb' }) + var test = request(app).post('/') + test.set('Content-Type', 'application/octet-stream') + test.set('Transfer-Encoding', 'chunked') + test.write(buf) + test.expect(413, done) + }) + + it('should accept number of bytes', function (done) { + var buf = Buffer.alloc(1028, '.') + var app = createApp({ limit: 1024 }) + var test = request(app).post('/') + test.set('Content-Type', 'application/octet-stream') + test.write(buf) + test.expect(413, done) + }) + + it('should not change when options altered', function (done) { + var buf = Buffer.alloc(1028, '.') + var options = { limit: '1kb' } + var app = createApp(options) + + options.limit = '100kb' + + var test = request(app).post('/') + test.set('Content-Type', 'application/octet-stream') + test.write(buf) + test.expect(413, done) + }) + + it('should not hang response', function (done) { + var buf = Buffer.alloc(10240, '.') + var app = createApp({ limit: '8kb' }) + var test = request(app).post('/') + test.set('Content-Type', 'application/octet-stream') + test.write(buf) + test.write(buf) + test.write(buf) + test.expect(413, done) + }) + }) + + describe('with inflate option', function () { + describe('when false', function () { + before(function () { + this.app = createApp({ inflate: false }) + }) + + it('should not accept content-encoding', function (done) { + var test = request(this.app).post('/') + test.set('Content-Encoding', 'gzip') + test.set('Content-Type', 'application/octet-stream') + test.write(Buffer.from('1f8b080000000000000bcb4bcc4db57db16e170099a4bad608000000', 'hex')) + test.expect(415, 'content encoding unsupported', done) + }) + }) + + describe('when true', function () { + before(function () { + this.app = createApp({ inflate: true }) + }) + + it('should accept content-encoding', function (done) { + var test = request(this.app).post('/') + test.set('Content-Encoding', 'gzip') + test.set('Content-Type', 'application/octet-stream') + test.write(Buffer.from('1f8b080000000000000bcb4bcc4db57db16e170099a4bad608000000', 'hex')) + test.expect(200, { buf: '6e616d653de8aeba' }, done) + }) + }) + }) + + describe('with type option', function () { + describe('when "application/vnd+octets"', function () { + before(function () { + this.app = createApp({ type: 'application/vnd+octets' }) + }) + + it('should parse for custom type', function (done) { + var test = request(this.app).post('/') + test.set('Content-Type', 'application/vnd+octets') + test.write(Buffer.from('000102', 'hex')) + test.expect(200, { buf: '000102' }, done) + }) + + it('should ignore standard type', function (done) { + var test = request(this.app).post('/') + test.set('Content-Type', 'application/octet-stream') + test.write(Buffer.from('000102', 'hex')) + test.expect(200, '{}', done) + }) + }) + + describe('when ["application/octet-stream", "application/vnd+octets"]', function () { + before(function () { + this.app = createApp({ + type: ['application/octet-stream', 'application/vnd+octets'] + }) + }) + + it('should parse "application/octet-stream"', function (done) { + var test = request(this.app).post('/') + test.set('Content-Type', 'application/octet-stream') + test.write(Buffer.from('000102', 'hex')) + test.expect(200, { buf: '000102' }, done) + }) + + it('should parse "application/vnd+octets"', function (done) { + var test = request(this.app).post('/') + test.set('Content-Type', 'application/vnd+octets') + test.write(Buffer.from('000102', 'hex')) + test.expect(200, { buf: '000102' }, done) + }) + + it('should ignore "application/x-foo"', function (done) { + var test = request(this.app).post('/') + test.set('Content-Type', 'application/x-foo') + test.write(Buffer.from('000102', 'hex')) + test.expect(200, '{}', done) + }) + }) + + describe('when a function', function () { + it('should parse when truthy value returned', function (done) { + var app = createApp({ type: accept }) + + function accept (req) { + return req.headers['content-type'] === 'application/vnd.octet' + } + + var test = request(app).post('/') + test.set('Content-Type', 'application/vnd.octet') + test.write(Buffer.from('000102', 'hex')) + test.expect(200, { buf: '000102' }, done) + }) + + it('should work without content-type', function (done) { + var app = createApp({ type: accept }) + + function accept (req) { + return true + } + + var test = request(app).post('/') + test.write(Buffer.from('000102', 'hex')) + test.expect(200, { buf: '000102' }, done) + }) + + it('should not invoke without a body', function (done) { + var app = createApp({ type: accept }) + + function accept (req) { + throw new Error('oops!') + } + + request(app) + .get('/') + .expect(404, done) + }) + }) + }) + + describe('with verify option', function () { + it('should assert value is function', function () { + assert.throws(createApp.bind(null, { verify: 'lol' }), + /TypeError: option verify must be function/) + }) + + it('should error from verify', function (done) { + var app = createApp({ verify: function (req, res, buf) { + if (buf[0] === 0x00) throw new Error('no leading null') + } }) + + var test = request(app).post('/') + test.set('Content-Type', 'application/octet-stream') + test.write(Buffer.from('000102', 'hex')) + test.expect(403, 'no leading null', done) + }) + + it('should allow custom codes', function (done) { + var app = createApp({ verify: function (req, res, buf) { + if (buf[0] !== 0x00) return + var err = new Error('no leading null') + err.status = 400 + throw err + } }) + + var test = request(app).post('/') + test.set('Content-Type', 'application/octet-stream') + test.write(Buffer.from('000102', 'hex')) + test.expect(400, 'no leading null', done) + }) + + it('should allow pass-through', function (done) { + var app = createApp({ verify: function (req, res, buf) { + if (buf[0] === 0x00) throw new Error('no leading null') + } }) + + var test = request(app).post('/') + test.set('Content-Type', 'application/octet-stream') + test.write(Buffer.from('0102', 'hex')) + test.expect(200, { buf: '0102' }, done) + }) + }) + + describe('charset', function () { + before(function () { + this.app = createApp() + }) + + it('should ignore charset', function (done) { + var test = request(this.app).post('/') + test.set('Content-Type', 'application/octet-stream; charset=utf-8') + test.write(Buffer.from('6e616d6520697320e8aeba', 'hex')) + test.expect(200, { buf: '6e616d6520697320e8aeba' }, done) + }) + }) + + describe('encoding', function () { + before(function () { + this.app = createApp({ limit: '10kb' }) + }) + + it('should parse without encoding', function (done) { + var test = request(this.app).post('/') + test.set('Content-Type', 'application/octet-stream') + test.write(Buffer.from('6e616d653de8aeba', 'hex')) + test.expect(200, { buf: '6e616d653de8aeba' }, done) + }) + + it('should support identity encoding', function (done) { + var test = request(this.app).post('/') + test.set('Content-Encoding', 'identity') + test.set('Content-Type', 'application/octet-stream') + test.write(Buffer.from('6e616d653de8aeba', 'hex')) + test.expect(200, { buf: '6e616d653de8aeba' }, done) + }) + + it('should support gzip encoding', function (done) { + var test = request(this.app).post('/') + test.set('Content-Encoding', 'gzip') + test.set('Content-Type', 'application/octet-stream') + test.write(Buffer.from('1f8b080000000000000bcb4bcc4db57db16e170099a4bad608000000', 'hex')) + test.expect(200, { buf: '6e616d653de8aeba' }, done) + }) + + it('should support deflate encoding', function (done) { + var test = request(this.app).post('/') + test.set('Content-Encoding', 'deflate') + test.set('Content-Type', 'application/octet-stream') + test.write(Buffer.from('789ccb4bcc4db57db16e17001068042f', 'hex')) + test.expect(200, { buf: '6e616d653de8aeba' }, done) + }) + + it('should be case-insensitive', function (done) { + var test = request(this.app).post('/') + test.set('Content-Encoding', 'GZIP') + test.set('Content-Type', 'application/octet-stream') + test.write(Buffer.from('1f8b080000000000000bcb4bcc4db57db16e170099a4bad608000000', 'hex')) + test.expect(200, { buf: '6e616d653de8aeba' }, done) + }) + + it('should fail on unknown encoding', function (done) { + var test = request(this.app).post('/') + test.set('Content-Encoding', 'nulls') + test.set('Content-Type', 'application/octet-stream') + test.write(Buffer.from('000000000000', 'hex')) + test.expect(415, 'unsupported content encoding "nulls"', done) + }) + }) +}) + +function createApp (options) { + var app = express() + + app.use(express.raw(options)) + + app.use(function (err, req, res, next) { + res.status(err.status || 500) + res.send(String(err[req.headers['x-error-property'] || 'message'])) + }) + + app.post('/', function (req, res) { + if (Buffer.isBuffer(req.body)) { + res.json({ buf: req.body.toString('hex') }) + } else { + res.json(req.body) + } + }) + + return app +} From 7f4e37f3ea0bf99287472dd72f48d12a3b3d0b71 Mon Sep 17 00:00:00 2001 From: Ilya Guterman Date: Mon, 23 Oct 2017 18:00:19 +0300 Subject: [PATCH 057/270] Add express.text to parse bodies into string closes #3455 --- History.md | 1 + lib/express.js | 1 + test/exports.js | 5 +++++ 3 files changed, 7 insertions(+) diff --git a/History.md b/History.md index 35259befeea..2410810d337 100644 --- a/History.md +++ b/History.md @@ -2,6 +2,7 @@ unreleased ========== * Add `express.raw` to parse bodies into `Buffer` + * Add `express.text` to parse bodies into string * Improve error message for non-strings to `res.sendFile` * Improve error message for `null`/`undefined` to `res.status` * Support multiple hosts in `X-Forwarded-Host` diff --git a/lib/express.js b/lib/express.js index f618ccc125a..d188a16db70 100644 --- a/lib/express.js +++ b/lib/express.js @@ -79,6 +79,7 @@ exports.json = bodyParser.json exports.query = require('./middleware/query'); exports.raw = bodyParser.raw exports.static = require('serve-static'); +exports.text = bodyParser.text exports.urlencoded = bodyParser.urlencoded /** diff --git a/test/exports.js b/test/exports.js index f43df44c34c..7624a8c8641 100644 --- a/test/exports.js +++ b/test/exports.js @@ -24,6 +24,11 @@ describe('exports', function(){ assert.equal(express.static.length, 2) }) + it('should expose text middleware', function () { + assert.equal(typeof express.text, 'function') + assert.equal(express.text.length, 1) + }) + it('should expose urlencoded middleware', function () { assert.equal(typeof express.urlencoded, 'function') assert.equal(express.urlencoded.length, 1) From bb5211fa1cdf6da767960c2a8aa97f8c8f31e9c5 Mon Sep 17 00:00:00 2001 From: Douglas Christopher Wilson Date: Wed, 8 May 2019 23:39:45 -0400 Subject: [PATCH 058/270] tests: add express.text test suite --- test/express.text.js | 441 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 441 insertions(+) create mode 100644 test/express.text.js diff --git a/test/express.text.js b/test/express.text.js new file mode 100644 index 00000000000..7c92f90e5aa --- /dev/null +++ b/test/express.text.js @@ -0,0 +1,441 @@ + +var assert = require('assert') +var Buffer = require('safe-buffer').Buffer +var express = require('..') +var request = require('supertest') + +describe('express.text()', function () { + before(function () { + this.app = createApp() + }) + + it('should parse text/plain', function (done) { + request(this.app) + .post('/') + .set('Content-Type', 'text/plain') + .send('user is tobi') + .expect(200, '"user is tobi"', done) + }) + + it('should 400 when invalid content-length', function (done) { + var app = express() + + app.use(function (req, res, next) { + req.headers['content-length'] = '20' // bad length + next() + }) + + app.use(express.text()) + + app.post('/', function (req, res) { + res.json(req.body) + }) + + request(app) + .post('/') + .set('Content-Type', 'text/plain') + .send('user') + .expect(400, /content length/, done) + }) + + it('should handle Content-Length: 0', function (done) { + request(createApp({ limit: '1kb' })) + .post('/') + .set('Content-Type', 'text/plain') + .set('Content-Length', '0') + .expect(200, '""', done) + }) + + it('should handle empty message-body', function (done) { + request(createApp({ limit: '1kb' })) + .post('/') + .set('Content-Type', 'text/plain') + .set('Transfer-Encoding', 'chunked') + .send('') + .expect(200, '""', done) + }) + + it('should handle duplicated middleware', function (done) { + var app = express() + + app.use(express.text()) + app.use(express.text()) + + app.post('/', function (req, res) { + res.json(req.body) + }) + + request(app) + .post('/') + .set('Content-Type', 'text/plain') + .send('user is tobi') + .expect(200, '"user is tobi"', done) + }) + + describe('with defaultCharset option', function () { + it('should change default charset', function (done) { + var app = createApp({ defaultCharset: 'koi8-r' }) + var test = request(app).post('/') + test.set('Content-Type', 'text/plain') + test.write(Buffer.from('6e616d6520697320cec5d4', 'hex')) + test.expect(200, '"name is нет"', done) + }) + + it('should honor content-type charset', function (done) { + var app = createApp({ defaultCharset: 'koi8-r' }) + var test = request(app).post('/') + test.set('Content-Type', 'text/plain; charset=utf-8') + test.write(Buffer.from('6e616d6520697320e8aeba', 'hex')) + test.expect(200, '"name is 论"', done) + }) + }) + + describe('with limit option', function () { + it('should 413 when over limit with Content-Length', function (done) { + var buf = Buffer.alloc(1028, '.') + request(createApp({ limit: '1kb' })) + .post('/') + .set('Content-Type', 'text/plain') + .set('Content-Length', '1028') + .send(buf.toString()) + .expect(413, done) + }) + + it('should 413 when over limit with chunked encoding', function (done) { + var buf = Buffer.alloc(1028, '.') + var app = createApp({ limit: '1kb' }) + var test = request(app).post('/') + test.set('Content-Type', 'text/plain') + test.set('Transfer-Encoding', 'chunked') + test.write(buf.toString()) + test.expect(413, done) + }) + + it('should accept number of bytes', function (done) { + var buf = Buffer.alloc(1028, '.') + request(createApp({ limit: 1024 })) + .post('/') + .set('Content-Type', 'text/plain') + .send(buf.toString()) + .expect(413, done) + }) + + it('should not change when options altered', function (done) { + var buf = Buffer.alloc(1028, '.') + var options = { limit: '1kb' } + var app = createApp(options) + + options.limit = '100kb' + + request(app) + .post('/') + .set('Content-Type', 'text/plain') + .send(buf.toString()) + .expect(413, done) + }) + + it('should not hang response', function (done) { + var buf = Buffer.alloc(10240, '.') + var app = createApp({ limit: '8kb' }) + var test = request(app).post('/') + test.set('Content-Type', 'text/plain') + test.write(buf) + test.write(buf) + test.write(buf) + test.expect(413, done) + }) + }) + + describe('with inflate option', function () { + describe('when false', function () { + before(function () { + this.app = createApp({ inflate: false }) + }) + + it('should not accept content-encoding', function (done) { + var test = request(this.app).post('/') + test.set('Content-Encoding', 'gzip') + test.set('Content-Type', 'text/plain') + test.write(Buffer.from('1f8b080000000000000bcb4bcc4d55c82c5678b16e170072b3e0200b000000', 'hex')) + test.expect(415, 'content encoding unsupported', done) + }) + }) + + describe('when true', function () { + before(function () { + this.app = createApp({ inflate: true }) + }) + + it('should accept content-encoding', function (done) { + var test = request(this.app).post('/') + test.set('Content-Encoding', 'gzip') + test.set('Content-Type', 'text/plain') + test.write(Buffer.from('1f8b080000000000000bcb4bcc4d55c82c5678b16e170072b3e0200b000000', 'hex')) + test.expect(200, '"name is 论"', done) + }) + }) + }) + + describe('with type option', function () { + describe('when "text/html"', function () { + before(function () { + this.app = createApp({ type: 'text/html' }) + }) + + it('should parse for custom type', function (done) { + request(this.app) + .post('/') + .set('Content-Type', 'text/html') + .send('tobi') + .expect(200, '"tobi"', done) + }) + + it('should ignore standard type', function (done) { + request(this.app) + .post('/') + .set('Content-Type', 'text/plain') + .send('user is tobi') + .expect(200, '{}', done) + }) + }) + + describe('when ["text/html", "text/plain"]', function () { + before(function () { + this.app = createApp({ type: ['text/html', 'text/plain'] }) + }) + + it('should parse "text/html"', function (done) { + request(this.app) + .post('/') + .set('Content-Type', 'text/html') + .send('tobi') + .expect(200, '"tobi"', done) + }) + + it('should parse "text/plain"', function (done) { + request(this.app) + .post('/') + .set('Content-Type', 'text/plain') + .send('tobi') + .expect(200, '"tobi"', done) + }) + + it('should ignore "text/xml"', function (done) { + request(this.app) + .post('/') + .set('Content-Type', 'text/xml') + .send('tobi') + .expect(200, '{}', done) + }) + }) + + describe('when a function', function () { + it('should parse when truthy value returned', function (done) { + var app = createApp({ type: accept }) + + function accept (req) { + return req.headers['content-type'] === 'text/vnd.something' + } + + request(app) + .post('/') + .set('Content-Type', 'text/vnd.something') + .send('user is tobi') + .expect(200, '"user is tobi"', done) + }) + + it('should work without content-type', function (done) { + var app = createApp({ type: accept }) + + function accept (req) { + return true + } + + var test = request(app).post('/') + test.write('user is tobi') + test.expect(200, '"user is tobi"', done) + }) + + it('should not invoke without a body', function (done) { + var app = createApp({ type: accept }) + + function accept (req) { + throw new Error('oops!') + } + + request(app) + .get('/') + .expect(404, done) + }) + }) + }) + + describe('with verify option', function () { + it('should assert value is function', function () { + assert.throws(createApp.bind(null, { verify: 'lol' }), + /TypeError: option verify must be function/) + }) + + it('should error from verify', function (done) { + var app = createApp({ verify: function (req, res, buf) { + if (buf[0] === 0x20) throw new Error('no leading space') + } }) + + request(app) + .post('/') + .set('Content-Type', 'text/plain') + .send(' user is tobi') + .expect(403, 'no leading space', done) + }) + + it('should allow custom codes', function (done) { + var app = createApp({ verify: function (req, res, buf) { + if (buf[0] !== 0x20) return + var err = new Error('no leading space') + err.status = 400 + throw err + } }) + + request(app) + .post('/') + .set('Content-Type', 'text/plain') + .send(' user is tobi') + .expect(400, 'no leading space', done) + }) + + it('should allow pass-through', function (done) { + var app = createApp({ verify: function (req, res, buf) { + if (buf[0] === 0x20) throw new Error('no leading space') + } }) + + request(app) + .post('/') + .set('Content-Type', 'text/plain') + .send('user is tobi') + .expect(200, '"user is tobi"', done) + }) + + it('should 415 on unknown charset prior to verify', function (done) { + var app = createApp({ verify: function (req, res, buf) { + throw new Error('unexpected verify call') + } }) + + var test = request(app).post('/') + test.set('Content-Type', 'text/plain; charset=x-bogus') + test.write(Buffer.from('00000000', 'hex')) + test.expect(415, 'unsupported charset "X-BOGUS"', done) + }) + }) + + describe('charset', function () { + before(function () { + this.app = createApp() + }) + + it('should parse utf-8', function (done) { + var test = request(this.app).post('/') + test.set('Content-Type', 'text/plain; charset=utf-8') + test.write(Buffer.from('6e616d6520697320e8aeba', 'hex')) + test.expect(200, '"name is 论"', done) + }) + + it('should parse codepage charsets', function (done) { + var test = request(this.app).post('/') + test.set('Content-Type', 'text/plain; charset=koi8-r') + test.write(Buffer.from('6e616d6520697320cec5d4', 'hex')) + test.expect(200, '"name is нет"', done) + }) + + it('should parse when content-length != char length', function (done) { + var test = request(this.app).post('/') + test.set('Content-Type', 'text/plain; charset=utf-8') + test.set('Content-Length', '11') + test.write(Buffer.from('6e616d6520697320e8aeba', 'hex')) + test.expect(200, '"name is 论"', done) + }) + + it('should default to utf-8', function (done) { + var test = request(this.app).post('/') + test.set('Content-Type', 'text/plain') + test.write(Buffer.from('6e616d6520697320e8aeba', 'hex')) + test.expect(200, '"name is 论"', done) + }) + + it('should 415 on unknown charset', function (done) { + var test = request(this.app).post('/') + test.set('Content-Type', 'text/plain; charset=x-bogus') + test.write(Buffer.from('00000000', 'hex')) + test.expect(415, 'unsupported charset "X-BOGUS"', done) + }) + }) + + describe('encoding', function () { + before(function () { + this.app = createApp({ limit: '10kb' }) + }) + + it('should parse without encoding', function (done) { + var test = request(this.app).post('/') + test.set('Content-Type', 'text/plain') + test.write(Buffer.from('6e616d6520697320e8aeba', 'hex')) + test.expect(200, '"name is 论"', done) + }) + + it('should support identity encoding', function (done) { + var test = request(this.app).post('/') + test.set('Content-Encoding', 'identity') + test.set('Content-Type', 'text/plain') + test.write(Buffer.from('6e616d6520697320e8aeba', 'hex')) + test.expect(200, '"name is 论"', done) + }) + + it('should support gzip encoding', function (done) { + var test = request(this.app).post('/') + test.set('Content-Encoding', 'gzip') + test.set('Content-Type', 'text/plain') + test.write(Buffer.from('1f8b080000000000000bcb4bcc4d55c82c5678b16e170072b3e0200b000000', 'hex')) + test.expect(200, '"name is 论"', done) + }) + + it('should support deflate encoding', function (done) { + var test = request(this.app).post('/') + test.set('Content-Encoding', 'deflate') + test.set('Content-Type', 'text/plain') + test.write(Buffer.from('789ccb4bcc4d55c82c5678b16e17001a6f050e', 'hex')) + test.expect(200, '"name is 论"', done) + }) + + it('should be case-insensitive', function (done) { + var test = request(this.app).post('/') + test.set('Content-Encoding', 'GZIP') + test.set('Content-Type', 'text/plain') + test.write(Buffer.from('1f8b080000000000000bcb4bcc4d55c82c5678b16e170072b3e0200b000000', 'hex')) + test.expect(200, '"name is 论"', done) + }) + + it('should fail on unknown encoding', function (done) { + var test = request(this.app).post('/') + test.set('Content-Encoding', 'nulls') + test.set('Content-Type', 'text/plain') + test.write(Buffer.from('000000000000', 'hex')) + test.expect(415, 'unsupported content encoding "nulls"', done) + }) + }) +}) + +function createApp (options) { + var app = express() + + app.use(express.text(options)) + + app.use(function (err, req, res, next) { + res.status(err.status || 500) + res.send(err.message) + }) + + app.post('/', function (req, res) { + res.json(req.body) + }) + + return app +} From 7b076bd8e1c428da4887856d34b813aba2732c19 Mon Sep 17 00:00:00 2001 From: Douglas Christopher Wilson Date: Thu, 9 May 2019 18:03:12 -0400 Subject: [PATCH 059/270] build: Node.js@6.17 --- .travis.yml | 2 +- appveyor.yml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.travis.yml b/.travis.yml index 36e7e75e568..b07c383bb18 100644 --- a/.travis.yml +++ b/.travis.yml @@ -7,7 +7,7 @@ node_js: - "3.3" - "4.9" - "5.12" - - "6.14" + - "6.17" - "7.10" - "8.12" - "9.11" diff --git a/appveyor.yml b/appveyor.yml index 4006a5e51d9..f970f8a7174 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -7,7 +7,7 @@ environment: - nodejs_version: "3.3" - nodejs_version: "4.9" - nodejs_version: "5.12" - - nodejs_version: "6.14" + - nodejs_version: "6.17" - nodejs_version: "7.10" - nodejs_version: "8.12" - nodejs_version: "9.11" From e91702872994523dbb9f7da1bf30854c5dfb834a Mon Sep 17 00:00:00 2001 From: Douglas Christopher Wilson Date: Thu, 9 May 2019 18:03:56 -0400 Subject: [PATCH 060/270] build: Node.js@8.16 --- .travis.yml | 2 +- appveyor.yml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.travis.yml b/.travis.yml index b07c383bb18..457029de675 100644 --- a/.travis.yml +++ b/.travis.yml @@ -9,7 +9,7 @@ node_js: - "5.12" - "6.17" - "7.10" - - "8.12" + - "8.16" - "9.11" - "10.12" matrix: diff --git a/appveyor.yml b/appveyor.yml index f970f8a7174..c2cd643e1cb 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -9,7 +9,7 @@ environment: - nodejs_version: "5.12" - nodejs_version: "6.17" - nodejs_version: "7.10" - - nodejs_version: "8.12" + - nodejs_version: "8.16" - nodejs_version: "9.11" - nodejs_version: "10.12" cache: From c754c8ad7b33a1d9ec6bec88bc44734c16c36167 Mon Sep 17 00:00:00 2001 From: Douglas Christopher Wilson Date: Thu, 9 May 2019 19:45:01 -0400 Subject: [PATCH 061/270] build: support Node.js 11.x --- .travis.yml | 3 +-- appveyor.yml | 1 + 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.travis.yml b/.travis.yml index 457029de675..b55dc4ae52f 100644 --- a/.travis.yml +++ b/.travis.yml @@ -12,10 +12,9 @@ node_js: - "8.16" - "9.11" - "10.12" + - "11.15" matrix: include: - - node_js: "11" - env: "NVM_NODEJS_ORG_MIRROR=https://nodejs.org/download/nightly" - node_js: "12" env: "NVM_NODEJS_ORG_MIRROR=https://nodejs.org/download/nightly" allow_failures: diff --git a/appveyor.yml b/appveyor.yml index c2cd643e1cb..82463dee7d1 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -12,6 +12,7 @@ environment: - nodejs_version: "8.16" - nodejs_version: "9.11" - nodejs_version: "10.12" + - nodejs_version: "11.15" cache: - node_modules install: From bc07a41693f8c7e9bde2bfb4cd5390ad6e3b1337 Mon Sep 17 00:00:00 2001 From: Douglas Christopher Wilson Date: Thu, 9 May 2019 22:09:56 -0400 Subject: [PATCH 062/270] deps: finalhandler@~1.1.2 --- History.md | 4 ++++ package.json | 2 +- 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/History.md b/History.md index 2410810d337..9ddfe35b884 100644 --- a/History.md +++ b/History.md @@ -18,6 +18,10 @@ unreleased - deps: raw-body@2.4.0 - deps: type-is@~1.6.17 * deps: content-disposition@0.5.3 + * deps: finalhandler@~1.1.2 + - Set stricter `Content-Security-Policy` header + - deps: parseurl@~1.3.3 + - deps: statuses@~1.5.0 * deps: parseurl@~1.3.3 * deps: proxy-addr@~2.0.5 - deps: ipaddr.js@1.9.0 diff --git a/package.json b/package.json index ef83d58d116..6f89e3369de 100644 --- a/package.json +++ b/package.json @@ -39,7 +39,7 @@ "encodeurl": "~1.0.2", "escape-html": "~1.0.3", "etag": "~1.8.1", - "finalhandler": "1.1.1", + "finalhandler": "~1.1.2", "fresh": "0.5.2", "merge-descriptors": "1.0.1", "methods": "~1.1.2", From 8267c4b72422e68654849a71bfb74141d77bb875 Mon Sep 17 00:00:00 2001 From: Douglas Christopher Wilson Date: Fri, 10 May 2019 23:49:13 -0400 Subject: [PATCH 063/270] deps: send@0.17.1 --- History.md | 4 +++- package.json | 2 +- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/History.md b/History.md index 9ddfe35b884..312f4b96952 100644 --- a/History.md +++ b/History.md @@ -27,10 +27,12 @@ unreleased - deps: ipaddr.js@1.9.0 * deps: qs@6.7.0 - Fix parsing array brackets after index - * deps: send@0.17.0 + * deps: send@0.17.1 + - Set stricter CSP header in redirect & error responses - deps: http-errors@~1.7.2 - deps: mime@1.6.0 - deps: ms@2.1.1 + - deps: range-parser@~1.2.1 - deps: statuses@~1.5.0 - perf: remove redundant `path.normalize` call * deps: serve-static@1.14.0 diff --git a/package.json b/package.json index 6f89e3369de..34904ac0002 100644 --- a/package.json +++ b/package.json @@ -50,7 +50,7 @@ "qs": "6.7.0", "range-parser": "~1.2.0", "safe-buffer": "5.1.2", - "send": "0.17.0", + "send": "0.17.1", "serve-static": "1.14.0", "setprototypeof": "1.1.1", "statuses": "~1.5.0", From 88f9733ffa58ce89bd5a9b207f0c8b4c2965fec6 Mon Sep 17 00:00:00 2001 From: Douglas Christopher Wilson Date: Sat, 11 May 2019 19:29:33 -0400 Subject: [PATCH 064/270] deps: serve-static@1.14.1 --- History.md | 5 +++-- package.json | 2 +- test/express.static.js | 2 +- 3 files changed, 5 insertions(+), 4 deletions(-) diff --git a/History.md b/History.md index 312f4b96952..b0685594a3b 100644 --- a/History.md +++ b/History.md @@ -35,9 +35,10 @@ unreleased - deps: range-parser@~1.2.1 - deps: statuses@~1.5.0 - perf: remove redundant `path.normalize` call - * deps: serve-static@1.14.0 + * deps: serve-static@1.14.1 + - Set stricter CSP header in redirect response - deps: parseurl@~1.3.3 - - deps: send@0.17.0 + - deps: send@0.17.1 * deps: setprototypeof@1.1.1 * deps: statuses@~1.5.0 - Add `103 Early Hints` diff --git a/package.json b/package.json index 34904ac0002..3a6a00d153b 100644 --- a/package.json +++ b/package.json @@ -51,7 +51,7 @@ "range-parser": "~1.2.0", "safe-buffer": "5.1.2", "send": "0.17.1", - "serve-static": "1.14.0", + "serve-static": "1.14.1", "setprototypeof": "1.1.1", "statuses": "~1.5.0", "type-is": "~1.6.18", diff --git a/test/express.static.js b/test/express.static.js index 7c9852243e6..485ee4c0c10 100644 --- a/test/express.static.js +++ b/test/express.static.js @@ -513,7 +513,7 @@ describe('express.static()', function () { it('should respond with default Content-Security-Policy', function (done) { request(this.app) .get('/users') - .expect('Content-Security-Policy', "default-src 'self'") + .expect('Content-Security-Policy', "default-src 'none'") .expect(301, done) }) From da6f701317d154e47921139257ffcefb15d15ca7 Mon Sep 17 00:00:00 2001 From: Douglas Christopher Wilson Date: Sun, 12 May 2019 22:01:06 -0400 Subject: [PATCH 065/270] deps: range-parser@~1.2.1 --- History.md | 1 + package.json | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/History.md b/History.md index b0685594a3b..ef9aec948c3 100644 --- a/History.md +++ b/History.md @@ -27,6 +27,7 @@ unreleased - deps: ipaddr.js@1.9.0 * deps: qs@6.7.0 - Fix parsing array brackets after index + * deps: range-parser@~1.2.1 * deps: send@0.17.1 - Set stricter CSP header in redirect & error responses - deps: http-errors@~1.7.2 diff --git a/package.json b/package.json index 3a6a00d153b..c722e230776 100644 --- a/package.json +++ b/package.json @@ -48,7 +48,7 @@ "path-to-regexp": "0.1.7", "proxy-addr": "~2.0.5", "qs": "6.7.0", - "range-parser": "~1.2.0", + "range-parser": "~1.2.1", "safe-buffer": "5.1.2", "send": "0.17.1", "serve-static": "1.14.1", From e502dde3c8c82ff107603f78d6cac9a33a699dd7 Mon Sep 17 00:00:00 2001 From: Douglas Christopher Wilson Date: Sun, 12 May 2019 22:09:35 -0400 Subject: [PATCH 066/270] build: Node.js@10.15 --- .travis.yml | 2 +- appveyor.yml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.travis.yml b/.travis.yml index b55dc4ae52f..4706b75982f 100644 --- a/.travis.yml +++ b/.travis.yml @@ -11,7 +11,7 @@ node_js: - "7.10" - "8.16" - "9.11" - - "10.12" + - "10.15" - "11.15" matrix: include: diff --git a/appveyor.yml b/appveyor.yml index 82463dee7d1..b222f6b7b75 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -11,7 +11,7 @@ environment: - nodejs_version: "7.10" - nodejs_version: "8.16" - nodejs_version: "9.11" - - nodejs_version: "10.12" + - nodejs_version: "10.15" - nodejs_version: "11.15" cache: - node_modules From 5266f3a5cb25fdd6846b76a727d601506791c4ce Mon Sep 17 00:00:00 2001 From: Douglas Christopher Wilson Date: Sun, 12 May 2019 22:15:36 -0400 Subject: [PATCH 067/270] build: test against Node.js 13.x nightly --- .travis.yml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.travis.yml b/.travis.yml index 4706b75982f..73422a7aa6c 100644 --- a/.travis.yml +++ b/.travis.yml @@ -17,6 +17,8 @@ matrix: include: - node_js: "12" env: "NVM_NODEJS_ORG_MIRROR=https://nodejs.org/download/nightly" + - node_js: "13" + env: "NVM_NODEJS_ORG_MIRROR=https://nodejs.org/download/nightly" allow_failures: # Allow the nightly installs to fail - env: "NVM_NODEJS_ORG_MIRROR=https://nodejs.org/download/nightly" From b9ecb9afe336ad00eb6e2dbc055e838649fe784f Mon Sep 17 00:00:00 2001 From: huadong zuo Date: Wed, 24 Apr 2019 19:44:09 +0800 Subject: [PATCH 068/270] build: support Node.js 12.x closes #3946 --- .travis.yml | 3 +-- appveyor.yml | 1 + 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.travis.yml b/.travis.yml index 73422a7aa6c..7b11677ec87 100644 --- a/.travis.yml +++ b/.travis.yml @@ -13,10 +13,9 @@ node_js: - "9.11" - "10.15" - "11.15" + - "12.2" matrix: include: - - node_js: "12" - env: "NVM_NODEJS_ORG_MIRROR=https://nodejs.org/download/nightly" - node_js: "13" env: "NVM_NODEJS_ORG_MIRROR=https://nodejs.org/download/nightly" allow_failures: diff --git a/appveyor.yml b/appveyor.yml index b222f6b7b75..84476a597d7 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -13,6 +13,7 @@ environment: - nodejs_version: "9.11" - nodejs_version: "10.15" - nodejs_version: "11.15" + - nodejs_version: "12.2" cache: - node_modules install: From efcb17dcb21699ef685eff4455a9443f707a4901 Mon Sep 17 00:00:00 2001 From: Douglas Christopher Wilson Date: Thu, 16 May 2019 09:55:26 -0400 Subject: [PATCH 069/270] deps: cookie@0.4.0 closes #3958 --- History.md | 2 ++ package.json | 2 +- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/History.md b/History.md index ef9aec948c3..da36866652c 100644 --- a/History.md +++ b/History.md @@ -18,6 +18,8 @@ unreleased - deps: raw-body@2.4.0 - deps: type-is@~1.6.17 * deps: content-disposition@0.5.3 + * deps: cookie@0.4.0 + - Add `SameSite=None` support * deps: finalhandler@~1.1.2 - Set stricter `Content-Security-Policy` header - deps: parseurl@~1.3.3 diff --git a/package.json b/package.json index c722e230776..b8b0b19e9ff 100644 --- a/package.json +++ b/package.json @@ -32,7 +32,7 @@ "body-parser": "1.19.0", "content-disposition": "0.5.3", "content-type": "~1.0.4", - "cookie": "0.3.1", + "cookie": "0.4.0", "cookie-signature": "1.0.6", "debug": "2.6.9", "depd": "~1.1.2", From 94e48a16f273963dc37829352b7381e4e9222315 Mon Sep 17 00:00:00 2001 From: Douglas Christopher Wilson Date: Thu, 16 May 2019 09:58:40 -0400 Subject: [PATCH 070/270] build: update example dependencies --- package.json | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/package.json b/package.json index b8b0b19e9ff..87b80ce33d2 100644 --- a/package.json +++ b/package.json @@ -60,12 +60,12 @@ }, "devDependencies": { "after": "0.8.2", - "connect-redis": "3.4.0", - "cookie-parser": "~1.4.3", - "cookie-session": "1.3.2", + "connect-redis": "3.4.1", + "cookie-parser": "~1.4.4", + "cookie-session": "1.3.3", "ejs": "2.6.1", "eslint": "2.13.1", - "express-session": "1.15.6", + "express-session": "1.16.1", "hbs": "4.0.4", "istanbul": "0.4.5", "marked": "0.6.2", From b8e50568af9c73ef1ade434e92c60d389868361d Mon Sep 17 00:00:00 2001 From: Douglas Christopher Wilson Date: Thu, 16 May 2019 10:04:24 -0400 Subject: [PATCH 071/270] tests: ignore unreachable line --- lib/response.js | 1 + 1 file changed, 1 insertion(+) diff --git a/lib/response.js b/lib/response.js index c1514901c57..a4f10cbb2e1 100644 --- a/lib/response.js +++ b/lib/response.js @@ -1135,6 +1135,7 @@ function stringify (value, replacer, spaces, escape) { return '\\u003e' case 0x26: return '\\u0026' + /* istanbul ignore next: unreachable default */ default: return c } From 9dadca2c64ae717063b0e9071143065896ebb676 Mon Sep 17 00:00:00 2001 From: Douglas Christopher Wilson Date: Thu, 16 May 2019 20:53:07 -0400 Subject: [PATCH 072/270] docs: remove Gratipay links --- Readme.md | 4 ---- 1 file changed, 4 deletions(-) diff --git a/Readme.md b/Readme.md index 81d8d91615e..1f91297312b 100644 --- a/Readme.md +++ b/Readme.md @@ -153,7 +153,3 @@ The current lead maintainer is [Douglas Christopher Wilson](https://github.com/d [appveyor-url]: https://ci.appveyor.com/project/dougwilson/express [coveralls-image]: https://img.shields.io/coveralls/expressjs/express/master.svg [coveralls-url]: https://coveralls.io/r/expressjs/express?branch=master -[gratipay-image-visionmedia]: https://img.shields.io/gratipay/visionmedia.svg -[gratipay-url-visionmedia]: https://gratipay.com/visionmedia/ -[gratipay-image-dougwilson]: https://img.shields.io/gratipay/dougwilson.svg -[gratipay-url-dougwilson]: https://gratipay.com/dougwilson/ From 10c7756764fbe969b307b15a72fd074479c00f8d Mon Sep 17 00:00:00 2001 From: Douglas Christopher Wilson Date: Thu, 16 May 2019 21:25:42 -0400 Subject: [PATCH 073/270] 4.17.0 --- History.md | 4 ++-- package.json | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/History.md b/History.md index da36866652c..cca851d2e0f 100644 --- a/History.md +++ b/History.md @@ -1,5 +1,5 @@ -unreleased -========== +4.17.0 / 2019-05-16 +=================== * Add `express.raw` to parse bodies into `Buffer` * Add `express.text` to parse bodies into string diff --git a/package.json b/package.json index 87b80ce33d2..726af2f6bab 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "express", "description": "Fast, unopinionated, minimalist web framework", - "version": "4.16.4", + "version": "4.17.0", "author": "TJ Holowaychuk ", "contributors": [ "Aaron Heckmann ", From eed05a1464485edc5154ce989a679ba602f11ed8 Mon Sep 17 00:00:00 2001 From: Douglas Christopher Wilson Date: Fri, 24 May 2019 23:20:52 -0400 Subject: [PATCH 074/270] build: Node.js@12.3 --- .travis.yml | 2 +- appveyor.yml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.travis.yml b/.travis.yml index 7b11677ec87..c3ebc583d6b 100644 --- a/.travis.yml +++ b/.travis.yml @@ -13,7 +13,7 @@ node_js: - "9.11" - "10.15" - "11.15" - - "12.2" + - "12.3" matrix: include: - node_js: "13" diff --git a/appveyor.yml b/appveyor.yml index 84476a597d7..24434cd14af 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -13,7 +13,7 @@ environment: - nodejs_version: "9.11" - nodejs_version: "10.15" - nodejs_version: "11.15" - - nodejs_version: "12.2" + - nodejs_version: "12.3" cache: - node_modules install: From 0a48e18056865364b2461b2ece7ccb2d1075d3c9 Mon Sep 17 00:00:00 2001 From: Douglas Christopher Wilson Date: Sat, 25 May 2019 18:15:13 -0400 Subject: [PATCH 075/270] Revert "Improve error message for null/undefined to res.status" fixes #3968 --- History.md | 5 +++++ lib/response.js | 4 ---- test/res.status.js | 32 -------------------------------- 3 files changed, 5 insertions(+), 36 deletions(-) diff --git a/History.md b/History.md index cca851d2e0f..631e0e5170b 100644 --- a/History.md +++ b/History.md @@ -1,3 +1,8 @@ +unreleased +========== + + * Revert "Improve error message for `null`/`undefined` to `res.status`" + 4.17.0 / 2019-05-16 =================== diff --git a/lib/response.js b/lib/response.js index a4f10cbb2e1..c9f08cd54f4 100644 --- a/lib/response.js +++ b/lib/response.js @@ -64,10 +64,6 @@ var charsetRegExp = /;\s*charset\s*=/; */ res.status = function status(code) { - if (code === undefined || code === null) { - throw new TypeError('code argument is required to res.status') - } - this.statusCode = code; return this; }; diff --git a/test/res.status.js b/test/res.status.js index 3f928ec0b0b..8c173a645c5 100644 --- a/test/res.status.js +++ b/test/res.status.js @@ -16,37 +16,5 @@ describe('res', function(){ .expect('Created') .expect(201, done); }) - - describe('when code is undefined', function () { - it('should throw a TypeError', function (done) { - var app = express() - - app.use(function (req, res) { - res.status(undefined).send('OK') - }) - - request(app) - .get('/') - .expect(500) - .expect(/TypeError: code argument is required to res.status/) - .end(done) - }) - }) - - describe('when code is null', function () { - it('should throw a TypeError', function (done) { - var app = express() - - app.use(function (req, res) { - res.status(null).send('OK') - }) - - request(app) - .get('/') - .expect(500) - .expect(/TypeError: code argument is required to res.status/) - .end(done) - }) - }) }) }) From e1b45ebd050b6f06aa38cda5aaf0c21708b0c71e Mon Sep 17 00:00:00 2001 From: Douglas Christopher Wilson Date: Sun, 26 May 2019 00:24:55 -0400 Subject: [PATCH 076/270] 4.17.1 --- History.md | 4 ++-- package.json | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/History.md b/History.md index 631e0e5170b..6e62a6ddb85 100644 --- a/History.md +++ b/History.md @@ -1,5 +1,5 @@ -unreleased -========== +4.17.1 / 2019-05-25 +=================== * Revert "Improve error message for `null`/`undefined` to `res.status`" diff --git a/package.json b/package.json index 726af2f6bab..2979d57a22f 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "express", "description": "Fast, unopinionated, minimalist web framework", - "version": "4.17.0", + "version": "4.17.1", "author": "TJ Holowaychuk ", "contributors": [ "Aaron Heckmann ", From dfa7b80642d3c30d911feeca9a460d1802d34a72 Mon Sep 17 00:00:00 2001 From: Douglas Christopher Wilson Date: Sun, 4 Aug 2019 22:03:22 -0400 Subject: [PATCH 077/270] build: Node.js@10.16 --- .travis.yml | 2 +- appveyor.yml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.travis.yml b/.travis.yml index c3ebc583d6b..6e144c24636 100644 --- a/.travis.yml +++ b/.travis.yml @@ -11,7 +11,7 @@ node_js: - "7.10" - "8.16" - "9.11" - - "10.15" + - "10.16" - "11.15" - "12.3" matrix: diff --git a/appveyor.yml b/appveyor.yml index 24434cd14af..3d775eb2112 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -11,7 +11,7 @@ environment: - nodejs_version: "7.10" - nodejs_version: "8.16" - nodejs_version: "9.11" - - nodejs_version: "10.15" + - nodejs_version: "10.16" - nodejs_version: "11.15" - nodejs_version: "12.3" cache: From 6506fb578ce06081f82c13fafafe35dfca7d9c86 Mon Sep 17 00:00:00 2001 From: Douglas Christopher Wilson Date: Sun, 4 Aug 2019 22:09:45 -0400 Subject: [PATCH 078/270] build: Node.js@12.7 --- .travis.yml | 2 +- appveyor.yml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.travis.yml b/.travis.yml index 6e144c24636..75907eed535 100644 --- a/.travis.yml +++ b/.travis.yml @@ -13,7 +13,7 @@ node_js: - "9.11" - "10.16" - "11.15" - - "12.3" + - "12.7" matrix: include: - node_js: "13" diff --git a/appveyor.yml b/appveyor.yml index 3d775eb2112..1675129d508 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -13,7 +13,7 @@ environment: - nodejs_version: "9.11" - nodejs_version: "10.16" - nodejs_version: "11.15" - - nodejs_version: "12.3" + - nodejs_version: "12.7" cache: - node_modules install: From 4efb49866df68a209808ac896ecbd6e53ae66ec7 Mon Sep 17 00:00:00 2001 From: Douglas Christopher Wilson Date: Sun, 4 Aug 2019 22:23:09 -0400 Subject: [PATCH 079/270] build: mocha@6.2.0 --- .travis.yml | 7 +++++-- appveyor.yml | 7 +++++-- package.json | 2 +- 3 files changed, 11 insertions(+), 5 deletions(-) diff --git a/.travis.yml b/.travis.yml index 75907eed535..6827cf0c3ee 100644 --- a/.travis.yml +++ b/.travis.yml @@ -37,9 +37,12 @@ before_install: # Setup Node.js version-specific dependencies - | # mocha for testing - # - use 3.x for Node.js < 6 - if [[ "$(cut -d. -f1 <<< "$TRAVIS_NODE_VERSION")" -lt 6 ]]; then + # - use 3.x for Node.js < 4 + # - use 5.x for Node.js < 6 + if [[ "$(cut -d. -f1 <<< "$TRAVIS_NODE_VERSION")" -lt 4 ]]; then npm install --silent --save-dev mocha@3.5.3 + elif [[ "$(cut -d. -f1 <<< "$TRAVIS_NODE_VERSION")" -lt 6 ]]; then + npm install --silent --save-dev mocha@5.2.0 fi - | # supertest for http calls diff --git a/appveyor.yml b/appveyor.yml index 1675129d508..16e9a084bbe 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -32,9 +32,12 @@ install: # Setup Node.js version-specific dependencies - ps: | # mocha for testing - # - use 3.x for Node.js < 6 - if ($env:nodejs_version.split(".")[0] -lt 6) { + # - use 3.x for Node.js < 4 + # - use 5.x for Node.js < 6 + if ($env:nodejs_version.split(".")[0] -lt 4) { npm install --silent --save-dev mocha@3.5.3 + } elseif ($env:nodejs_version.split(".")[0] -lt 6) { + npm install --silent --save-dev mocha@5.2.0 } - ps: | # supertest for http calls diff --git a/package.json b/package.json index 2979d57a22f..3b26c45471f 100644 --- a/package.json +++ b/package.json @@ -70,7 +70,7 @@ "istanbul": "0.4.5", "marked": "0.6.2", "method-override": "3.0.0", - "mocha": "5.2.0", + "mocha": "6.2.0", "morgan": "1.9.1", "multiparty": "4.2.1", "pbkdf2-password": "1.2.1", From 741e3f81af6264e4d67a59528a64b40f96ca5911 Mon Sep 17 00:00:00 2001 From: Douglas Christopher Wilson Date: Sun, 10 Nov 2019 22:04:12 -0500 Subject: [PATCH 080/270] build: Node.js@10.17 --- .travis.yml | 2 +- appveyor.yml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.travis.yml b/.travis.yml index 6827cf0c3ee..878ee8377f9 100644 --- a/.travis.yml +++ b/.travis.yml @@ -11,7 +11,7 @@ node_js: - "7.10" - "8.16" - "9.11" - - "10.16" + - "10.17" - "11.15" - "12.7" matrix: diff --git a/appveyor.yml b/appveyor.yml index 16e9a084bbe..a89d339f7ae 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -11,7 +11,7 @@ environment: - nodejs_version: "7.10" - nodejs_version: "8.16" - nodejs_version: "9.11" - - nodejs_version: "10.16" + - nodejs_version: "10.17" - nodejs_version: "11.15" - nodejs_version: "12.7" cache: From 866ffd67d785f88616b7444871c05995a21cff0e Mon Sep 17 00:00:00 2001 From: Douglas Christopher Wilson Date: Sun, 10 Nov 2019 22:09:43 -0500 Subject: [PATCH 081/270] build: Node.js@12.13 --- .travis.yml | 2 +- appveyor.yml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.travis.yml b/.travis.yml index 878ee8377f9..fbbfbcdb7d1 100644 --- a/.travis.yml +++ b/.travis.yml @@ -13,7 +13,7 @@ node_js: - "9.11" - "10.17" - "11.15" - - "12.7" + - "12.13" matrix: include: - node_js: "13" diff --git a/appveyor.yml b/appveyor.yml index a89d339f7ae..01e3bdd5683 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -13,7 +13,7 @@ environment: - nodejs_version: "9.11" - nodejs_version: "10.17" - nodejs_version: "11.15" - - nodejs_version: "12.7" + - nodejs_version: "12.13" cache: - node_modules install: From 668d029a14acfb031652c54bf32f705d2dde64ee Mon Sep 17 00:00:00 2001 From: Douglas Christopher Wilson Date: Sun, 10 Nov 2019 22:15:49 -0500 Subject: [PATCH 082/270] build: mocha@6.2.2 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 3b26c45471f..ac9152b67d1 100644 --- a/package.json +++ b/package.json @@ -70,7 +70,7 @@ "istanbul": "0.4.5", "marked": "0.6.2", "method-override": "3.0.0", - "mocha": "6.2.0", + "mocha": "6.2.2", "morgan": "1.9.1", "multiparty": "4.2.1", "pbkdf2-password": "1.2.1", From 95735a6fccd165fb6113daae9259ca26efc52171 Mon Sep 17 00:00:00 2001 From: Douglas Christopher Wilson Date: Sun, 10 Nov 2019 22:21:57 -0500 Subject: [PATCH 083/270] build: supertest@3.4.2 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index ac9152b67d1..65ab7da19e5 100644 --- a/package.json +++ b/package.json @@ -75,7 +75,7 @@ "multiparty": "4.2.1", "pbkdf2-password": "1.2.1", "should": "13.2.3", - "supertest": "3.3.0", + "supertest": "3.4.2", "vhost": "~3.0.2" }, "engines": { From e757fa003938dddc19f1ed3c447fffe1062f1508 Mon Sep 17 00:00:00 2001 From: Douglas Christopher Wilson Date: Thu, 9 Jan 2020 18:30:57 -0500 Subject: [PATCH 084/270] build: Node.js@8.17 --- .travis.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index fbbfbcdb7d1..8c4529fe06b 100644 --- a/.travis.yml +++ b/.travis.yml @@ -9,7 +9,7 @@ node_js: - "5.12" - "6.17" - "7.10" - - "8.16" + - "8.17" - "9.11" - "10.17" - "11.15" From 55831bbd08736b8424d26a8ee22039e06a8816aa Mon Sep 17 00:00:00 2001 From: Douglas Christopher Wilson Date: Thu, 9 Jan 2020 18:37:52 -0500 Subject: [PATCH 085/270] build: Node.js@10.18 --- .travis.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index 8c4529fe06b..9ab31558d86 100644 --- a/.travis.yml +++ b/.travis.yml @@ -11,7 +11,7 @@ node_js: - "7.10" - "8.17" - "9.11" - - "10.17" + - "10.18" - "11.15" - "12.13" matrix: From f1e8a877f4f70dbf0a12e2471671be68e35e31d8 Mon Sep 17 00:00:00 2001 From: Douglas Christopher Wilson Date: Thu, 9 Jan 2020 18:40:28 -0500 Subject: [PATCH 086/270] build: Node.js@12.14 --- .travis.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index 9ab31558d86..8d7cf6c22da 100644 --- a/.travis.yml +++ b/.travis.yml @@ -13,7 +13,7 @@ node_js: - "9.11" - "10.18" - "11.15" - - "12.13" + - "12.14" matrix: include: - node_js: "13" From f0cbdeadf695d4e5dc1332666e864ce82845a555 Mon Sep 17 00:00:00 2001 From: Douglas Christopher Wilson Date: Thu, 9 Jan 2020 18:58:52 -0500 Subject: [PATCH 087/270] build: mocha@7.0.0 --- .travis.yml | 3 +++ appveyor.yml | 3 +++ package.json | 2 +- 3 files changed, 7 insertions(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index 8d7cf6c22da..8bda1d8d9f8 100644 --- a/.travis.yml +++ b/.travis.yml @@ -39,10 +39,13 @@ before_install: # mocha for testing # - use 3.x for Node.js < 4 # - use 5.x for Node.js < 6 + # - use 6.x for Node.js < 8 if [[ "$(cut -d. -f1 <<< "$TRAVIS_NODE_VERSION")" -lt 4 ]]; then npm install --silent --save-dev mocha@3.5.3 elif [[ "$(cut -d. -f1 <<< "$TRAVIS_NODE_VERSION")" -lt 6 ]]; then npm install --silent --save-dev mocha@5.2.0 + elif [[ "$(cut -d. -f1 <<< "$TRAVIS_NODE_VERSION")" -lt 8 ]]; then + npm install --silent --save-dev mocha@6.2.2 fi - | # supertest for http calls diff --git a/appveyor.yml b/appveyor.yml index 01e3bdd5683..b95b8e2d5ac 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -34,10 +34,13 @@ install: # mocha for testing # - use 3.x for Node.js < 4 # - use 5.x for Node.js < 6 + # - use 6.x for Node.js < 8 if ($env:nodejs_version.split(".")[0] -lt 4) { npm install --silent --save-dev mocha@3.5.3 } elseif ($env:nodejs_version.split(".")[0] -lt 6) { npm install --silent --save-dev mocha@5.2.0 + } elseif ($env:nodejs_version.split(".")[0] -lt 8) { + npm install --silent --save-dev mocha@6.2.2 } - ps: | # supertest for http calls diff --git a/package.json b/package.json index 65ab7da19e5..a988bb5fc0a 100644 --- a/package.json +++ b/package.json @@ -70,7 +70,7 @@ "istanbul": "0.4.5", "marked": "0.6.2", "method-override": "3.0.0", - "mocha": "6.2.2", + "mocha": "7.0.0", "morgan": "1.9.1", "multiparty": "4.2.1", "pbkdf2-password": "1.2.1", From 87bc4ef7638c38abf6c2bca10a07a0b1e4fd4a60 Mon Sep 17 00:00:00 2001 From: Douglas Christopher Wilson Date: Tue, 11 Feb 2020 23:10:15 -0500 Subject: [PATCH 088/270] build: update example dependencies --- package.json | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/package.json b/package.json index a988bb5fc0a..725e3ff0538 100644 --- a/package.json +++ b/package.json @@ -60,15 +60,15 @@ }, "devDependencies": { "after": "0.8.2", - "connect-redis": "3.4.1", + "connect-redis": "3.4.2", "cookie-parser": "~1.4.4", "cookie-session": "1.3.3", - "ejs": "2.6.1", + "ejs": "2.7.2", "eslint": "2.13.1", - "express-session": "1.16.1", - "hbs": "4.0.4", + "express-session": "1.17.0", + "hbs": "4.1.0", "istanbul": "0.4.5", - "marked": "0.6.2", + "marked": "0.7.0", "method-override": "3.0.0", "mocha": "7.0.0", "morgan": "1.9.1", From 872aa4741c95c2ba15e0dd40cd54ed6eb6c83e3e Mon Sep 17 00:00:00 2001 From: Douglas Christopher Wilson Date: Wed, 19 Feb 2020 00:27:51 -0500 Subject: [PATCH 089/270] build: Node.js@10.19 --- .travis.yml | 2 +- appveyor.yml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.travis.yml b/.travis.yml index 8bda1d8d9f8..78cdba19380 100644 --- a/.travis.yml +++ b/.travis.yml @@ -11,7 +11,7 @@ node_js: - "7.10" - "8.17" - "9.11" - - "10.18" + - "10.19" - "11.15" - "12.14" matrix: diff --git a/appveyor.yml b/appveyor.yml index b95b8e2d5ac..1b579dd8292 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -11,7 +11,7 @@ environment: - nodejs_version: "7.10" - nodejs_version: "8.16" - nodejs_version: "9.11" - - nodejs_version: "10.17" + - nodejs_version: "10.19" - nodejs_version: "11.15" - nodejs_version: "12.13" cache: From 22d5b7ed108e2e67f694c126278a87bd28f89fe7 Mon Sep 17 00:00:00 2001 From: Douglas Christopher Wilson Date: Wed, 19 Feb 2020 00:32:14 -0500 Subject: [PATCH 090/270] build: Node.js@12.16 --- .travis.yml | 2 +- appveyor.yml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.travis.yml b/.travis.yml index 78cdba19380..7178dd4bf20 100644 --- a/.travis.yml +++ b/.travis.yml @@ -13,7 +13,7 @@ node_js: - "9.11" - "10.19" - "11.15" - - "12.14" + - "12.16" matrix: include: - node_js: "13" diff --git a/appveyor.yml b/appveyor.yml index 1b579dd8292..9d3b80fafae 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -13,7 +13,7 @@ environment: - nodejs_version: "9.11" - nodejs_version: "10.19" - nodejs_version: "11.15" - - nodejs_version: "12.13" + - nodejs_version: "12.16" cache: - node_modules install: From d967675852b06384c8ebfc065430a8e215fc08f5 Mon Sep 17 00:00:00 2001 From: Douglas Christopher Wilson Date: Wed, 19 Feb 2020 00:49:36 -0500 Subject: [PATCH 091/270] build: mocha@7.0.1 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 725e3ff0538..2110419476e 100644 --- a/package.json +++ b/package.json @@ -70,7 +70,7 @@ "istanbul": "0.4.5", "marked": "0.7.0", "method-override": "3.0.0", - "mocha": "7.0.0", + "mocha": "7.0.1", "morgan": "1.9.1", "multiparty": "4.2.1", "pbkdf2-password": "1.2.1", From 2d519077ea6c7c52a16098c7cf6d8d667a863c7b Mon Sep 17 00:00:00 2001 From: Douglas Christopher Wilson Date: Tue, 17 Mar 2020 20:31:10 -0400 Subject: [PATCH 092/270] build: supertest@4.0.2 --- .travis.yml | 3 +++ appveyor.yml | 3 +++ package.json | 2 +- 3 files changed, 7 insertions(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index 7178dd4bf20..6cae565f990 100644 --- a/.travis.yml +++ b/.travis.yml @@ -50,8 +50,11 @@ before_install: - | # supertest for http calls # - use 2.0.0 for Node.js < 4 + # - use 3.4.2 for Node.js < 6 if [[ "$(cut -d. -f1 <<< "$TRAVIS_NODE_VERSION")" -lt 4 ]]; then npm install --silent --save-dev supertest@2.0.0 + elif [[ "$(cut -d. -f1 <<< "$TRAVIS_NODE_VERSION")" -lt 6 ]]; then + npm install --silent --save-dev supertest@3.4.2 fi # Update Node.js modules - | diff --git a/appveyor.yml b/appveyor.yml index 9d3b80fafae..94d25b3d535 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -45,8 +45,11 @@ install: - ps: | # supertest for http calls # - use 2.0.0 for Node.js < 4 + # - use 3.4.2 for Node.js < 6 if ($env:nodejs_version.split(".")[0] -lt 4) { npm install --silent --save-dev supertest@2.0.0 + } elseif ($env:nodejs_version.split(".")[0] -lt 6) { + npm install --silent --save-dev supertest@3.4.2 } # Update Node.js modules - ps: | diff --git a/package.json b/package.json index 2110419476e..6296ac68a33 100644 --- a/package.json +++ b/package.json @@ -75,7 +75,7 @@ "multiparty": "4.2.1", "pbkdf2-password": "1.2.1", "should": "13.2.3", - "supertest": "3.4.2", + "supertest": "4.0.2", "vhost": "~3.0.2" }, "engines": { From 65aff94ec62b9f550aa7fb82cd8a1dd7b7da0bfc Mon Sep 17 00:00:00 2001 From: Douglas Christopher Wilson Date: Tue, 17 Mar 2020 20:37:16 -0400 Subject: [PATCH 093/270] build: remove deprecated Travis CI directive --- .travis.yml | 1 - 1 file changed, 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index 6cae565f990..37735595818 100644 --- a/.travis.yml +++ b/.travis.yml @@ -21,7 +21,6 @@ matrix: allow_failures: # Allow the nightly installs to fail - env: "NVM_NODEJS_ORG_MIRROR=https://nodejs.org/download/nightly" -sudo: false cache: directories: - node_modules From 47c1d2a8168a4e6b060f32c1d15ba8ed2f52a99b Mon Sep 17 00:00:00 2001 From: Chang Wang Date: Thu, 1 Mar 2018 19:37:45 -0500 Subject: [PATCH 094/270] docs: point npm downloads badge to npm charts of express closes #3579 --- Readme.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Readme.md b/Readme.md index 1f91297312b..dae3ddb9ce9 100644 --- a/Readme.md +++ b/Readme.md @@ -146,7 +146,7 @@ The current lead maintainer is [Douglas Christopher Wilson](https://github.com/d [npm-image]: https://img.shields.io/npm/v/express.svg [npm-url]: https://npmjs.org/package/express [downloads-image]: https://img.shields.io/npm/dm/express.svg -[downloads-url]: https://npmjs.org/package/express +[downloads-url]: https://npmcharts.com/compare/express?minimal=true [travis-image]: https://img.shields.io/travis/expressjs/express/master.svg?label=linux [travis-url]: https://travis-ci.org/expressjs/express [appveyor-image]: https://img.shields.io/appveyor/ci/dougwilson/express/master.svg?label=windows From 4b4fa26298c3ee9eb7385cc04a1f33f670fd82bb Mon Sep 17 00:00:00 2001 From: yanokenken Date: Sun, 26 May 2019 00:24:55 -0400 Subject: [PATCH 095/270] docs: add npm init hint to install section --- Readme.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/Readme.md b/Readme.md index dae3ddb9ce9..9b15b440d72 100644 --- a/Readme.md +++ b/Readme.md @@ -27,6 +27,9 @@ This is a [Node.js](https://nodejs.org/en/) module available through the Before installing, [download and install Node.js](https://nodejs.org/en/download/). Node.js 0.10 or higher is required. +If this is a brand new project, make sure to create a `package.json` first with +the [`npm init` command](https://docs.npmjs.com/creating-a-package-json-file). + Installation is done using the [`npm install` command](https://docs.npmjs.com/getting-started/installing-npm-packages-locally): From 3f1dcb96e0ad0145b47a4b1e37bfbbfa6abaf602 Mon Sep 17 00:00:00 2001 From: Aditya Srivastava Date: Tue, 22 Jan 2019 17:44:37 +0530 Subject: [PATCH 096/270] examples: add viewport and charset where missing closes #3860 --- examples/auth/views/head.ejs | 2 ++ examples/ejs/views/header.html | 1 + examples/error-pages/views/error_header.ejs | 2 ++ examples/error-pages/views/index.ejs | 2 ++ examples/mvc/controllers/pet/views/edit.ejs | 2 ++ examples/mvc/controllers/pet/views/show.ejs | 2 ++ examples/mvc/controllers/user/views/edit.hbs | 2 ++ examples/mvc/controllers/user/views/list.hbs | 2 ++ examples/mvc/controllers/user/views/show.hbs | 2 ++ examples/mvc/views/404.ejs | 1 + examples/mvc/views/5xx.ejs | 1 + examples/route-separation/views/header.ejs | 1 + examples/search/public/index.html | 1 + examples/view-locals/views/index.ejs | 1 + 14 files changed, 22 insertions(+) diff --git a/examples/auth/views/head.ejs b/examples/auth/views/head.ejs index 0a919f49296..65386267d0d 100644 --- a/examples/auth/views/head.ejs +++ b/examples/auth/views/head.ejs @@ -1,6 +1,8 @@ + + <%= title %>