From 8ee3420f0fa064fe8bd6476492cc928f1833f90e Mon Sep 17 00:00:00 2001 From: Douglas Christopher Wilson Date: Sun, 20 Feb 2022 23:43:02 -0500 Subject: [PATCH 001/130] tests: fix req.acceptsEncodings tests --- test/req.acceptsEncodings.js | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/test/req.acceptsEncodings.js b/test/req.acceptsEncodings.js index c36934290a..9f8973cdfb 100644 --- a/test/req.acceptsEncodings.js +++ b/test/req.acceptsEncodings.js @@ -10,8 +10,8 @@ describe('req', function(){ app.get('/', function (req, res) { res.send({ - gzip: req.acceptsEncoding('gzip'), - deflate: req.acceptsEncoding('deflate') + gzip: req.acceptsEncodings('gzip'), + deflate: req.acceptsEncodings('deflate') }) }) @@ -26,7 +26,7 @@ describe('req', function(){ app.get('/', function (req, res) { res.send({ - bogus: req.acceptsEncoding('bogus') + bogus: req.acceptsEncodings('bogus') }) }) From d8ed591117295f528c59d0f0367064ffde96d427 Mon Sep 17 00:00:00 2001 From: Douglas Christopher Wilson Date: Sun, 20 Feb 2022 23:49:42 -0500 Subject: [PATCH 002/130] tests: fix req.acceptsLanguage tests --- test/req.acceptsLanguage.js | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/test/req.acceptsLanguage.js b/test/req.acceptsLanguage.js index 816be244eb..39bd73c483 100644 --- a/test/req.acceptsLanguage.js +++ b/test/req.acceptsLanguage.js @@ -10,8 +10,8 @@ describe('req', function(){ app.get('/', function (req, res) { res.send({ - 'en-us': req.acceptsLanguages('en-us'), - en: req.acceptsLanguages('en') + 'en-us': req.acceptsLanguage('en-us'), + en: req.acceptsLanguage('en') }) }) @@ -26,7 +26,7 @@ describe('req', function(){ app.get('/', function (req, res) { res.send({ - es: req.acceptsLanguages('es') + es: req.acceptsLanguage('es') }) }) @@ -42,9 +42,9 @@ describe('req', function(){ app.get('/', function (req, res) { res.send({ - en: req.acceptsLanguages('en'), - es: req.acceptsLanguages('es'), - jp: req.acceptsLanguages('jp') + en: req.acceptsLanguage('en'), + es: req.acceptsLanguage('es'), + jp: req.acceptsLanguage('jp') }) }) From 7df0c840e07d17a2268a2ab18e6db7656b203b78 Mon Sep 17 00:00:00 2001 From: Douglas Christopher Wilson Date: Mon, 21 Feb 2022 19:07:26 -0500 Subject: [PATCH 003/130] tests: fix up app.locals tests --- test/app.locals.js | 32 ++++++++++++++------------------ 1 file changed, 14 insertions(+), 18 deletions(-) diff --git a/test/app.locals.js b/test/app.locals.js index 88f83c9483..657b4b75c7 100644 --- a/test/app.locals.js +++ b/test/app.locals.js @@ -2,28 +2,24 @@ var assert = require('assert') var express = require('../') -var should = require('should') describe('app', function(){ - describe('.locals(obj)', function(){ - it('should merge locals', function(){ - var app = express(); - should(Object.keys(app.locals)).eql(['settings']) - app.locals.user = 'tobi'; - app.locals.age = 2; - should(Object.keys(app.locals)).eql(['settings', 'user', 'age']) - assert.strictEqual(app.locals.user, 'tobi') - assert.strictEqual(app.locals.age, 2) + describe('.locals', function () { + it('should default object', function () { + var app = express() + assert.ok(app.locals) + assert.strictEqual(typeof app.locals, 'object') }) - }) - describe('.locals.settings', function(){ - it('should expose app settings', function(){ - var app = express(); - app.set('title', 'House of Manny'); - var obj = app.locals.settings; - should(obj).have.property('env', 'test') - should(obj).have.property('title', 'House of Manny') + describe('.settings', function () { + it('should contain app settings ', function () { + var app = express() + app.set('title', 'Express') + assert.ok(app.locals.settings) + assert.strictEqual(typeof app.locals.settings, 'object') + assert.strictEqual(app.locals.settings, app.settings) + assert.strictEqual(app.locals.settings.title, 'Express') + }) }) }) }) From 9967ffbdc2b90fd651e2a687fabc0d53a1065f82 Mon Sep 17 00:00:00 2001 From: Douglas Christopher Wilson Date: Mon, 21 Feb 2022 19:23:25 -0500 Subject: [PATCH 004/130] tests: update res.append to verify separate header lines --- test/res.append.js | 71 ++++++++++++++++++++++++++-------------------- 1 file changed, 41 insertions(+), 30 deletions(-) diff --git a/test/res.append.js b/test/res.append.js index 5b12e35b69..8f72598bf5 100644 --- a/test/res.append.js +++ b/test/res.append.js @@ -1,31 +1,29 @@ 'use strict' +var assert = require('assert') var express = require('..') var request = require('supertest') -var should = require('should') describe('res', function () { - // note about these tests: "Link" and "X-*" are chosen because - // the common node.js versions white list which _incoming_ - // headers can appear multiple times; there is no such white list - // for outgoing, though describe('.append(field, val)', function () { it('should append multiple headers', function (done) { var app = express() app.use(function (req, res, next) { - res.append('Link', '') + res.append('Set-Cookie', 'foo=bar') next() }) app.use(function (req, res) { - res.append('Link', '') + res.append('Set-Cookie', 'fizz=buzz') res.end() }) request(app) - .get('/') - .expect('Link', ', ', done) + .get('/') + .expect(200) + .expect(shouldHaveHeaderValues('Set-Cookie', ['foo=bar', 'fizz=buzz'])) + .end(done) }) it('should accept array of values', function (done) { @@ -37,51 +35,54 @@ describe('res', function () { }) request(app) - .get('/') - .expect(function (res) { - should(res.headers['set-cookie']).eql(['foo=bar', 'fizz=buzz']) - }) - .expect(200, done) + .get('/') + .expect(200) + .expect(shouldHaveHeaderValues('Set-Cookie', ['foo=bar', 'fizz=buzz'])) + .end(done) }) it('should get reset by res.set(field, val)', function (done) { var app = express() app.use(function (req, res, next) { - res.append('Link', '') - res.append('Link', '') + res.append('Set-Cookie', 'foo=bar') + res.append('Set-Cookie', 'fizz=buzz') next() }) app.use(function (req, res) { - res.set('Link', '') + res.set('Set-Cookie', 'pet=tobi') res.end() }); request(app) - .get('/') - .expect('Link', '', done) + .get('/') + .expect(200) + .expect(shouldHaveHeaderValues('Set-Cookie', ['pet=tobi'])) + .end(done) }) it('should work with res.set(field, val) first', function (done) { var app = express() app.use(function (req, res, next) { - res.set('Link', '') + res.set('Set-Cookie', 'foo=bar') next() }) app.use(function(req, res){ - res.append('Link', '') + res.append('Set-Cookie', 'fizz=buzz') res.end() }) request(app) - .get('/') - .expect('Link', ', ', done) + .get('/') + .expect(200) + .expect(shouldHaveHeaderValues('Set-Cookie', ['foo=bar', 'fizz=buzz'])) + .end(done) }) - it('should work with cookies', function (done) { + it('should work together with res.cookie', function (done) { var app = express() app.use(function (req, res, next) { @@ -90,16 +91,26 @@ describe('res', function () { }) app.use(function (req, res) { - res.append('Set-Cookie', 'bar=baz') + res.append('Set-Cookie', 'fizz=buzz') res.end() }) request(app) - .get('/') - .expect(function (res) { - should(res.headers['set-cookie']).eql(['foo=bar; Path=/', 'bar=baz']) - }) - .expect(200, done) + .get('/') + .expect(200) + .expect(shouldHaveHeaderValues('Set-Cookie', ['foo=bar; Path=/', 'fizz=buzz'])) + .end(done) }) }) }) + +function shouldHaveHeaderValues (key, values) { + return function (res) { + var headers = res.headers[key.toLowerCase()] + assert.ok(headers, 'should have header "' + key + '"') + assert.strictEqual(headers.length, values.length, 'should have ' + values.length + ' occurances of "' + key + '"') + for (var i = 0; i < values.length; i++) { + assert.strictEqual(headers[i], values[i]) + } + } +} From bc5ca055094bb48dedbb4a4c828dbe5b2d450616 Mon Sep 17 00:00:00 2001 From: Douglas Christopher Wilson Date: Mon, 21 Feb 2022 19:54:52 -0500 Subject: [PATCH 005/130] tests: remove usage of should --- package.json | 1 - test/Route.js | 34 +++++++++++++++++----------------- test/exports.js | 21 ++++++++++----------- test/mocha.opts | 2 -- test/res.sendFile.js | 23 ++++++++++------------- test/utils.js | 12 +++++++++--- 6 files changed, 46 insertions(+), 47 deletions(-) delete mode 100644 test/mocha.opts diff --git a/package.json b/package.json index 2fb6ebaab0..61e91899e6 100644 --- a/package.json +++ b/package.json @@ -76,7 +76,6 @@ "nyc": "15.1.0", "pbkdf2-password": "1.2.1", "resolve-path": "1.4.0", - "should": "13.2.3", "supertest": "6.2.2", "vhost": "~3.0.2" }, diff --git a/test/Route.js b/test/Route.js index 005b4634e9..8e7ddbdbcc 100644 --- a/test/Route.js +++ b/test/Route.js @@ -1,7 +1,7 @@ 'use strict' var after = require('after'); -var should = require('should'); +var assert = require('assert') var express = require('../') , Route = express.Route , methods = require('methods') @@ -25,7 +25,7 @@ describe('Route', function(){ route.dispatch(req, {}, function (err) { if (err) return done(err); - should(req.called).be.ok() + assert.ok(req.called) done(); }); }) @@ -35,7 +35,7 @@ describe('Route', function(){ var route = new Route('/foo'); var cb = after(methods.length, function (err) { if (err) return done(err); - count.should.equal(methods.length); + assert.strictEqual(count, methods.length) done(); }); @@ -66,7 +66,7 @@ describe('Route', function(){ route.dispatch(req, {}, function (err) { if (err) return done(err); - req.count.should.equal(2); + assert.strictEqual(req.count, 2) done(); }); }) @@ -84,7 +84,7 @@ describe('Route', function(){ route.dispatch(req, {}, function (err) { if (err) return done(err); - should(req.called).be.ok() + assert.ok(req.called) done(); }); }) @@ -104,7 +104,7 @@ describe('Route', function(){ route.dispatch(req, {}, function (err) { if (err) return done(err); - should(req.called).be.true() + assert.ok(req.called) done(); }); }) @@ -130,7 +130,7 @@ describe('Route', function(){ route.dispatch(req, {}, function (err) { if (err) return done(err); - req.order.should.equal('abc'); + assert.strictEqual(req.order, 'abc') done(); }); }) @@ -156,9 +156,9 @@ describe('Route', function(){ }); route.dispatch(req, {}, function (err) { - should(err).be.ok() - should(err.message).equal('foobar'); - req.order.should.equal('a'); + assert.ok(err) + assert.strictEqual(err.message, 'foobar') + assert.strictEqual(req.order, 'a') done(); }); }) @@ -182,9 +182,9 @@ describe('Route', function(){ }); route.dispatch(req, {}, function (err) { - should(err).be.ok() - should(err.message).equal('foobar'); - req.order.should.equal('a'); + assert.ok(err) + assert.strictEqual(err.message, 'foobar') + assert.strictEqual(req.order, 'a') done(); }); }); @@ -208,7 +208,7 @@ describe('Route', function(){ route.dispatch(req, {}, function (err) { if (err) return done(err); - should(req.message).equal('oops'); + assert.strictEqual(req.message, 'oops') done(); }); }); @@ -222,8 +222,8 @@ describe('Route', function(){ }); route.dispatch(req, {}, function(err){ - should(err).be.ok() - err.message.should.equal('boom!'); + assert.ok(err) + assert.strictEqual(err.message, 'boom!') done(); }); }); @@ -234,7 +234,7 @@ describe('Route', function(){ route.all(function(err, req, res, next){ // this should not execute - true.should.be.false() + throw new Error('should not be called') }); route.dispatch(req, {}, done); diff --git a/test/exports.js b/test/exports.js index 98d7936594..5ab0f885ce 100644 --- a/test/exports.js +++ b/test/exports.js @@ -3,11 +3,10 @@ var assert = require('assert') var express = require('../'); var request = require('supertest'); -var should = require('should'); describe('exports', function(){ it('should expose Router', function(){ - express.Router.should.be.a.Function() + assert.strictEqual(typeof express.Router, 'function') }) it('should expose json middleware', function () { @@ -36,20 +35,23 @@ describe('exports', function(){ }) it('should expose the application prototype', function(){ - express.application.set.should.be.a.Function() + assert.strictEqual(typeof express.application, 'object') + assert.strictEqual(typeof express.application.set, 'function') }) it('should expose the request prototype', function(){ - express.request.accepts.should.be.a.Function() + assert.strictEqual(typeof express.request, 'object') + assert.strictEqual(typeof express.request.accepts, 'function') }) it('should expose the response prototype', function(){ - express.response.send.should.be.a.Function() + assert.strictEqual(typeof express.response, 'object') + assert.strictEqual(typeof express.response.send, 'function') }) it('should permit modifying the .application prototype', function(){ express.application.foo = function(){ return 'bar'; }; - express().foo().should.equal('bar'); + assert.strictEqual(express().foo(), 'bar') }) it('should permit modifying the .request prototype', function(done){ @@ -79,10 +81,7 @@ describe('exports', function(){ }) it('should throw on old middlewares', function(){ - var error; - try { express.bodyParser; } catch (e) { error = e; } - should(error).have.property('message'); - error.message.should.containEql('middleware'); - error.message.should.containEql('bodyParser'); + assert.throws(function () { express.bodyParser() }, /Error:.*middleware.*bodyParser/) + assert.throws(function () { express.limit() }, /Error:.*middleware.*limit/) }) }) diff --git a/test/mocha.opts b/test/mocha.opts deleted file mode 100644 index 1e065ec52d..0000000000 --- a/test/mocha.opts +++ /dev/null @@ -1,2 +0,0 @@ ---require should ---slow 20 diff --git a/test/res.sendFile.js b/test/res.sendFile.js index c7fc93a76d..c676fc41ee 100644 --- a/test/res.sendFile.js +++ b/test/res.sendFile.js @@ -7,7 +7,6 @@ var express = require('../') , assert = require('assert'); var onFinished = require('on-finished'); var path = require('path'); -var should = require('should'); var fixtures = path.join(__dirname, 'fixtures'); var utils = require('./support/utils'); @@ -359,15 +358,13 @@ describe('res', function(){ app.use(function (req, res) { res.sendFile(path.resolve(fixtures, 'does-not-exist'), function (err) { - should(err).be.ok() - err.status.should.equal(404); - res.send('got it'); + res.send(err ? 'got ' + err.status + ' error' : 'no error') }); }); request(app) - .get('/') - .expect(200, 'got it', done); + .get('/') + .expect(200, 'got 404 error', done) }) }) @@ -539,7 +536,7 @@ describe('res', function(){ app.use(function(req, res){ res.sendfile('test/fixtures/user.html', function(err){ assert(!res.headersSent); - req.socket.listeners('error').should.have.length(1); // node's original handler + assert.strictEqual(req.socket.listeners('error').length, 1) // node's original handler done(); }); @@ -783,12 +780,12 @@ describe('res', function(){ }); request(app) - .get('/') - .end(function(err, res){ - res.statusCode.should.equal(404); - calls.should.equal(1); - done(); - }); + .get('/') + .expect(404, function (err) { + if (err) return done(err) + assert.strictEqual(calls, 1) + done() + }) }) describe('with non-GET', function(){ diff --git a/test/utils.js b/test/utils.js index f0cb3c3761..9a38ede656 100644 --- a/test/utils.js +++ b/test/utils.js @@ -2,7 +2,6 @@ var assert = require('assert'); var Buffer = require('safe-buffer').Buffer -var should = require('should') var utils = require('../lib/utils'); describe('utils.etag(body, encoding)', function(){ @@ -91,7 +90,14 @@ describe('utils.isAbsolute()', function(){ describe('utils.flatten(arr)', function(){ it('should flatten an array', function(){ var arr = ['one', ['two', ['three', 'four'], 'five']]; - should(utils.flatten(arr)) - .eql(['one', 'two', 'three', 'four', 'five']) + var flat = utils.flatten(arr) + + assert.strictEqual(flat.length, 5) + assert.strictEqual(flat[0], 'one') + assert.strictEqual(flat[1], 'two') + assert.strictEqual(flat[2], 'three') + assert.strictEqual(flat[3], 'four') + assert.strictEqual(flat[4], 'five') + assert.ok(flat.every(function (v) { return typeof v === 'string' })) }) }) From 18f782bba97157ab2e0ab754b404388e524915fd Mon Sep 17 00:00:00 2001 From: Douglas Christopher Wilson Date: Wed, 23 Feb 2022 00:18:36 -0500 Subject: [PATCH 006/130] tests: remove duplicate utils --- test/res.download.js | 36 ++++++++++-------------------------- test/res.redirect.js | 33 +++++++++++++-------------------- test/res.send.js | 34 +++++++++------------------------- test/res.sendFile.js | 26 ++++++++------------------ 4 files changed, 40 insertions(+), 89 deletions(-) diff --git a/test/res.download.js b/test/res.download.js index ce0ee088ba..29a687a4fd 100644 --- a/test/res.download.js +++ b/test/res.download.js @@ -1,10 +1,10 @@ 'use strict' var after = require('after'); -var assert = require('assert'); var Buffer = require('safe-buffer').Buffer var express = require('..'); var request = require('supertest'); +var utils = require('./support/utils') describe('res', function(){ describe('.download(path)', function(){ @@ -129,12 +129,12 @@ describe('res', function(){ }) request(app) - .get('/') - .expect(200) - .expect('Content-Disposition', 'attachment; filename="document"') - .expect('Cache-Control', 'public, max-age=14400') - .expect(shouldHaveBody(Buffer.from('tobi'))) - .end(done) + .get('/') + .expect(200) + .expect('Content-Disposition', 'attachment; filename="document"') + .expect('Cache-Control', 'public, max-age=14400') + .expect(utils.shouldHaveBody(Buffer.from('tobi'))) + .end(done) }) describe('when options.headers contains Content-Disposition', function () { @@ -207,25 +207,9 @@ describe('res', function(){ }); request(app) - .get('/') - .expect(shouldNotHaveHeader('Content-Disposition')) - .expect(200, 'failed', done); + .get('/') + .expect(utils.shouldNotHaveHeader('Content-Disposition')) + .expect(200, 'failed', done) }) }) }) - -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 be7c773bee..5ffc7e48f1 100644 --- a/test/res.redirect.js +++ b/test/res.redirect.js @@ -1,6 +1,5 @@ 'use strict' -var assert = require('assert') var express = require('..'); var request = require('supertest'); var utils = require('./support/utils'); @@ -86,11 +85,11 @@ describe('res', function(){ }); request(app) - .head('/') - .expect(302) - .expect('Location', 'http://google.com') - .expect(shouldNotHaveBody()) - .end(done) + .head('/') + .expect(302) + .expect('Location', 'http://google.com') + .expect(utils.shouldNotHaveBody()) + .end(done) }) }) @@ -199,20 +198,14 @@ 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(shouldNotHaveBody()) - .end(done) + .get('/') + .set('Accept', 'application/octet-stream') + .expect(302) + .expect('location', 'http://google.com') + .expect('content-length', '0') + .expect(utils.shouldNotHaveHeader('Content-Type')) + .expect(utils.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 8f849f8069..6ba5542288 100644 --- a/test/res.send.js +++ b/test/res.send.js @@ -188,11 +188,11 @@ describe('res', function(){ }); request(app) - .get('/') - .expect(200) - .expect('Content-Type', 'application/octet-stream') - .expect(shouldHaveBody(Buffer.from('hello'))) - .end(done) + .get('/') + .expect(200) + .expect('Content-Type', 'application/octet-stream') + .expect(utils.shouldHaveBody(Buffer.from('hello'))) + .end(done) }) it('should set ETag', function (done) { @@ -259,10 +259,10 @@ describe('res', function(){ }); request(app) - .head('/') - .expect(200) - .expect(shouldNotHaveBody()) - .end(done) + .head('/') + .expect(200) + .expect(utils.shouldNotHaveBody()) + .end(done) }) }) @@ -578,19 +578,3 @@ 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 c676fc41ee..538d6b9d34 100644 --- a/test/res.sendFile.js +++ b/test/res.sendFile.js @@ -165,10 +165,10 @@ describe('res', function(){ var app = createApp(path.resolve(__dirname, 'fixtures/.name'), { dotfiles: 'allow' }); request(app) - .get('/') - .expect(200) - .expect(shouldHaveBody(Buffer.from('tobi'))) - .end(done) + .get('/') + .expect(200) + .expect(utils.shouldHaveBody(Buffer.from('tobi'))) + .end(done) }); }); @@ -570,10 +570,10 @@ describe('res', function(){ }); request(app) - .get('/') - .expect(200) - .expect(shouldHaveBody(Buffer.from('tobi'))) - .end(done) + .get('/') + .expect(200) + .expect(utils.shouldHaveBody(Buffer.from('tobi'))) + .end(done) }) it('should accept headers option', function(done){ @@ -828,13 +828,3 @@ 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 8da8f79c44cefd96f0a194904288658abce13d9d Mon Sep 17 00:00:00 2001 From: Douglas Christopher Wilson Date: Wed, 23 Feb 2022 00:20:34 -0500 Subject: [PATCH 007/130] tests: fix callback in res.download test --- test/res.download.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/res.download.js b/test/res.download.js index 29a687a4fd..1322b0a31f 100644 --- a/test/res.download.js +++ b/test/res.download.js @@ -107,7 +107,7 @@ describe('res', function(){ var options = {} app.use(function (req, res) { - res.download('test/fixtures/user.html', 'document', options, done) + res.download('test/fixtures/user.html', 'document', options, cb) }) request(app) From cf9f662655ec8e2b90c5e5d561e0daa083908aa0 Mon Sep 17 00:00:00 2001 From: Douglas Christopher Wilson Date: Thu, 24 Feb 2022 00:17:01 -0500 Subject: [PATCH 008/130] tests: fix position of res.sendfile(path, options) test --- test/res.sendFile.js | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/test/res.sendFile.js b/test/res.sendFile.js index 538d6b9d34..67981fa127 100644 --- a/test/res.sendFile.js +++ b/test/res.sendFile.js @@ -803,19 +803,19 @@ describe('res', function(){ }) }) }) -}) -describe('.sendfile(path, options)', function () { - it('should pass options to send module', function (done) { - var app = express() + describe('.sendfile(path, options)', function () { + it('should pass options to send module', function (done) { + var app = express() - app.use(function (req, res) { - res.sendfile(path.resolve(fixtures, 'name.txt'), { start: 0, end: 1 }) - }) + app.use(function (req, res) { + res.sendfile(path.resolve(fixtures, 'name.txt'), { start: 0, end: 1 }) + }) - request(app) - .get('/') - .expect(200, 'to', done) + request(app) + .get('/') + .expect(200, 'to', done) + }) }) }) From d0e166c3c6eaf80871b7f38839ea90e048452844 Mon Sep 17 00:00:00 2001 From: apeltop Date: Mon, 28 Feb 2022 16:38:06 +0900 Subject: [PATCH 009/130] docs: fix typo in private api jsdoc closes #4843 --- lib/response.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/response.js b/lib/response.js index ba02008522..ccf8d91b2c 100644 --- a/lib/response.js +++ b/lib/response.js @@ -1113,7 +1113,7 @@ function sendfile(res, file, options, callback) { * ability to escape characters that can trigger HTML sniffing. * * @param {*} value - * @param {function} replaces + * @param {function} replacer * @param {number} spaces * @param {boolean} escape * @returns {string} From ea66a9b81bdd95b83d0035d8cbb41e6eacc6ea5b Mon Sep 17 00:00:00 2001 From: Douglas Christopher Wilson Date: Mon, 28 Feb 2022 21:15:08 -0500 Subject: [PATCH 010/130] docs: update link to github actions ci --- Readme.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Readme.md b/Readme.md index b60d588c41..61c4d5219d 100644 --- a/Readme.md +++ b/Readme.md @@ -147,7 +147,7 @@ The current lead maintainer is [Douglas Christopher Wilson](https://github.com/d [MIT](LICENSE) [ci-image]: https://img.shields.io/github/workflow/status/expressjs/express/ci/master.svg?label=linux -[ci-url]: https://github.com/expressjs/express/actions?query=workflow%3Aci +[ci-url]: https://github.com/expressjs/express/actions/workflows/ci.yml [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 From 4ed35b42026e09bcdcd9da821f172c238fb36cb5 Mon Sep 17 00:00:00 2001 From: Douglas Christopher Wilson Date: Mon, 28 Feb 2022 21:23:49 -0500 Subject: [PATCH 011/130] docs: switch badges to badgen --- Readme.md | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/Readme.md b/Readme.md index 61c4d5219d..51c0fb108e 100644 --- a/Readme.md +++ b/Readme.md @@ -2,9 +2,9 @@ Fast, unopinionated, minimalist web framework for [node](http://nodejs.org). - [![NPM Version][npm-image]][npm-url] - [![NPM Downloads][downloads-image]][downloads-url] - [![Linux Build][ci-image]][ci-url] + [![NPM Version][npm-version-image]][npm-url] + [![NPM Downloads][npm-downloads-image]][npm-downloads-url] + [![Linux Build][github-actions-ci-image]][github-actions-ci-url] [![Windows Build][appveyor-image]][appveyor-url] [![Test Coverage][coveralls-image]][coveralls-url] @@ -146,13 +146,13 @@ The current lead maintainer is [Douglas Christopher Wilson](https://github.com/d [MIT](LICENSE) -[ci-image]: https://img.shields.io/github/workflow/status/expressjs/express/ci/master.svg?label=linux -[ci-url]: https://github.com/expressjs/express/actions/workflows/ci.yml -[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://npmcharts.com/compare/express?minimal=true -[appveyor-image]: https://img.shields.io/appveyor/ci/dougwilson/express/master.svg?label=windows +[appveyor-image]: https://badgen.net/appveyor/ci/dougwilson/express/master?label=windows [appveyor-url]: https://ci.appveyor.com/project/dougwilson/express -[coveralls-image]: https://img.shields.io/coveralls/expressjs/express/master.svg +[coveralls-image]: https://badgen.net/coveralls/c/github/expressjs/express/master [coveralls-url]: https://coveralls.io/r/expressjs/express?branch=master +[github-actions-ci-image]: https://badgen.net/github/checks/expressjs/express/master?label=linux +[github-actions-ci-url]: https://github.com/expressjs/express/actions/workflows/ci.yml +[npm-downloads-image]: https://badgen.net/npm/dm/express +[npm-downloads-url]: https://npmcharts.com/compare/express?minimal=true +[npm-url]: https://npmjs.org/package/express +[npm-version-image]: https://badgen.net/npm/v/express From 07aa91f7cbfc3bc2443b292488ab8e3aafb92605 Mon Sep 17 00:00:00 2001 From: Douglas Christopher Wilson Date: Mon, 28 Feb 2022 21:52:57 -0500 Subject: [PATCH 012/130] docs: consolidate contributing in readme --- Readme.md | 47 ++++++++++++++++++++++++++--------------------- 1 file changed, 26 insertions(+), 21 deletions(-) diff --git a/Readme.md b/Readme.md index 51c0fb108e..b0a7950e8a 100644 --- a/Readme.md +++ b/Readme.md @@ -4,9 +4,6 @@ [![NPM Version][npm-version-image]][npm-url] [![NPM Downloads][npm-downloads-image]][npm-downloads-url] - [![Linux Build][github-actions-ci-image]][github-actions-ci-url] - [![Windows Build][appveyor-image]][appveyor-url] - [![Test Coverage][coveralls-image]][coveralls-url] ```js const express = require('express') @@ -33,7 +30,7 @@ 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): -```bash +```console $ npm install express ``` @@ -61,35 +58,31 @@ for more information. **PROTIP** Be sure to read [Migrating from 3.x to 4.x](https://github.com/expressjs/express/wiki/Migrating-from-3.x-to-4.x) as well as [New features in 4.x](https://github.com/expressjs/express/wiki/New-features-in-4.x). -### Security Issues - -If you discover a security vulnerability in Express, please see [Security Policies and Procedures](Security.md). - ## Quick Start The quickest way to get started with express is to utilize the executable [`express(1)`](https://github.com/expressjs/generator) to generate an application as shown below: Install the executable. The executable's major version will match Express's: -```bash +```console $ npm install -g express-generator@4 ``` Create the app: -```bash +```console $ express /tmp/foo && cd /tmp/foo ``` Install dependencies: -```bash +```console $ npm install ``` Start the server: -```bash +```console $ npm start ``` @@ -109,7 +102,7 @@ $ npm start To view the examples, clone the Express repo and install the dependencies: -```bash +```console $ git clone git://github.com/expressjs/express.git --depth 1 $ cd express $ npm install @@ -117,23 +110,35 @@ $ npm install Then run whichever example you want: -```bash +```console $ node examples/content-negotiation ``` -## Tests +## Contributing + + [![Linux Build][github-actions-ci-image]][github-actions-ci-url] + [![Windows Build][appveyor-image]][appveyor-url] + [![Test Coverage][coveralls-image]][coveralls-url] + +The Express.js project welcomes all constructive contributions. Contributions take many forms, +from code for bug fixes and enhancements, to additions and fixes to documentation, additional +tests, triaging incoming pull requests and issues, and more! + +See the [Contributing Guide](Contributing.md) for more technical details on contributing. - To run the test suite, first install the dependencies, then run `npm test`: +### Security Issues + +If you discover a security vulnerability in Express, please see [Security Policies and Procedures](Security.md). -```bash +### Running Tests + +To run the test suite, first install the dependencies, then run `npm test`: + +```console $ npm install $ npm test ``` -## Contributing - -[Contributing Guide](Contributing.md) - ## People The original author of Express is [TJ Holowaychuk](https://github.com/tj) From e8594c35715a764afda8e56fd1b60cb2fe147f64 Mon Sep 17 00:00:00 2001 From: Steven Date: Thu, 9 Aug 2018 15:00:29 -0400 Subject: [PATCH 013/130] docs: add install size badge closes #3710 --- Readme.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/Readme.md b/Readme.md index b0a7950e8a..720bf38922 100644 --- a/Readme.md +++ b/Readme.md @@ -3,6 +3,7 @@ Fast, unopinionated, minimalist web framework for [node](http://nodejs.org). [![NPM Version][npm-version-image]][npm-url] + [![NPM Install Size][npm-install-size-image]][npm-install-size-url] [![NPM Downloads][npm-downloads-image]][npm-downloads-url] ```js @@ -159,5 +160,7 @@ The current lead maintainer is [Douglas Christopher Wilson](https://github.com/d [github-actions-ci-url]: https://github.com/expressjs/express/actions/workflows/ci.yml [npm-downloads-image]: https://badgen.net/npm/dm/express [npm-downloads-url]: https://npmcharts.com/compare/express?minimal=true +[npm-install-size-image]: https://badgen.net/packagephobia/install/express +[npm-install-size-url]: https://packagephobia.com/result?p=express [npm-url]: https://npmjs.org/package/express [npm-version-image]: https://badgen.net/npm/v/express From 291993d73c0c92c1ccce2dad264c86bdd1b4fe4b Mon Sep 17 00:00:00 2001 From: Douglas Christopher Wilson Date: Tue, 1 Mar 2022 00:22:09 -0500 Subject: [PATCH 014/130] tests: expand res.sendFile options tests --- test/res.sendFile.js | 712 ++++++++++++++++++++++++++++++++++-------- test/support/utils.js | 14 + 2 files changed, 596 insertions(+), 130 deletions(-) diff --git a/test/res.sendFile.js b/test/res.sendFile.js index 67981fa127..e828c17e25 100644 --- a/test/res.sendFile.js +++ b/test/res.sendFile.js @@ -28,6 +28,14 @@ describe('res', function(){ .expect(500, /TypeError: path must be a string to res.sendFile/, done) }) + it('should error for non-absolute path', function (done) { + var app = createApp('name.txt') + + request(app) + .get('/') + .expect(500, /TypeError: path must be absolute/, done) + }) + it('should transfer a file', function (done) { var app = createApp(path.resolve(fixtures, 'name.txt')); @@ -90,6 +98,23 @@ describe('res', function(){ .expect(404, done); }); + it('should send cache-control by default', function (done) { + var app = createApp(path.resolve(__dirname, 'fixtures/name.txt')) + + request(app) + .get('/') + .expect('Cache-Control', 'public, max-age=0') + .expect(200, done) + }) + + it('should not serve dotfiles by default', function (done) { + var app = createApp(path.resolve(__dirname, 'fixtures/.name')) + + request(app) + .get('/') + .expect(404, done) + }) + it('should not override manual content-types', function (done) { var app = express(); @@ -131,136 +156,6 @@ describe('res', function(){ server.close(cb) }) }) - - describe('with "cacheControl" option', function () { - it('should enable cacheControl by default', function (done) { - var app = createApp(path.resolve(__dirname, 'fixtures/name.txt')) - - request(app) - .get('/') - .expect('Cache-Control', 'public, max-age=0') - .expect(200, done) - }) - - it('should accept cacheControl option', function (done) { - var app = createApp(path.resolve(__dirname, 'fixtures/name.txt'), { cacheControl: false }) - - request(app) - .get('/') - .expect(utils.shouldNotHaveHeader('Cache-Control')) - .expect(200, done) - }) - }) - - describe('with "dotfiles" option', function () { - it('should not serve dotfiles by default', function (done) { - var app = createApp(path.resolve(__dirname, 'fixtures/.name')); - - request(app) - .get('/') - .expect(404, done); - }); - - it('should accept dotfiles option', function(done){ - var app = createApp(path.resolve(__dirname, 'fixtures/.name'), { dotfiles: 'allow' }); - - request(app) - .get('/') - .expect(200) - .expect(utils.shouldHaveBody(Buffer.from('tobi'))) - .end(done) - }); - }); - - describe('with "headers" option', function () { - it('should accept headers option', function (done) { - var headers = { - 'x-success': 'sent', - 'x-other': 'done' - }; - var app = createApp(path.resolve(__dirname, 'fixtures/name.txt'), { headers: headers }); - - request(app) - .get('/') - .expect('x-success', 'sent') - .expect('x-other', 'done') - .expect(200, done); - }); - - it('should ignore headers option on 404', function (done) { - var headers = { 'x-success': 'sent' }; - var app = createApp(path.resolve(__dirname, 'fixtures/does-not-exist'), { headers: headers }); - - request(app) - .get('/') - .expect(utils.shouldNotHaveHeader('X-Success')) - .expect(404, done); - }); - }); - - describe('with "immutable" option', function () { - it('should add immutable cache-control directive', function (done) { - var app = createApp(path.resolve(__dirname, 'fixtures/name.txt'), { - immutable: true, - maxAge: '4h' - }) - - request(app) - .get('/') - .expect('Cache-Control', 'public, max-age=14400, immutable') - .expect(200, done) - }) - }) - - describe('with "maxAge" option', function () { - it('should set cache-control max-age from number', function (done) { - var app = createApp(path.resolve(__dirname, 'fixtures/name.txt'), { - maxAge: 14400000 - }) - - request(app) - .get('/') - .expect('Cache-Control', 'public, max-age=14400') - .expect(200, done) - }) - - it('should set cache-control max-age from string', function (done) { - var app = createApp(path.resolve(__dirname, 'fixtures/name.txt'), { - maxAge: '4h' - }) - - request(app) - .get('/') - .expect('Cache-Control', 'public, max-age=14400') - .expect(200, done) - }) - }) - - describe('with "root" option', function () { - it('should not transfer relative with without', function (done) { - var app = createApp('test/fixtures/name.txt'); - - request(app) - .get('/') - .expect(500, /must be absolute/, done); - }) - - it('should serve relative to "root"', function (done) { - var app = createApp('name.txt', {root: fixtures}); - - request(app) - .get('/') - .expect(200, 'tobi', done); - }) - - it('should disallow requesting out of "root"', function (done) { - var app = createApp('foo/../../user.html', {root: fixtures}); - - request(app) - .get('/') - .expect(403, done); - }) - }) }) describe('.sendFile(path, fn)', function () { @@ -374,6 +269,563 @@ describe('res', function(){ .get('/') .expect(200, 'to', done) }) + + describe('with "acceptRanges" option', function () { + describe('when true', function () { + it('should advertise byte range accepted', function (done) { + var app = express() + + app.use(function (req, res) { + res.sendFile(path.resolve(fixtures, 'nums.txt'), { + acceptRanges: true + }) + }) + + request(app) + .get('/') + .expect(200) + .expect('Accept-Ranges', 'bytes') + .expect('123456789') + .end(done) + }) + + it('should respond to range request', function (done) { + var app = express() + + app.use(function (req, res) { + res.sendFile(path.resolve(fixtures, 'nums.txt'), { + acceptRanges: true + }) + }) + + request(app) + .get('/') + .set('Range', 'bytes=0-4') + .expect(206, '12345', done) + }) + }) + + describe('when false', function () { + it('should not advertise accept-ranges', function (done) { + var app = express() + + app.use(function (req, res) { + res.sendFile(path.resolve(fixtures, 'nums.txt'), { + acceptRanges: false + }) + }) + + request(app) + .get('/') + .expect(200) + .expect(utils.shouldNotHaveHeader('Accept-Ranges')) + .end(done) + }) + + it('should not honor range requests', function (done) { + var app = express() + + app.use(function (req, res) { + res.sendFile(path.resolve(fixtures, 'nums.txt'), { + acceptRanges: false + }) + }) + + request(app) + .get('/') + .set('Range', 'bytes=0-4') + .expect(200, '123456789', done) + }) + }) + }) + + describe('with "cacheControl" option', function () { + describe('when true', function () { + it('should send cache-control header', function (done) { + var app = express() + + app.use(function (req, res) { + res.sendFile(path.resolve(fixtures, 'user.html'), { + cacheControl: true + }) + }) + + request(app) + .get('/') + .expect(200) + .expect('Cache-Control', 'public, max-age=0') + .end(done) + }) + }) + + describe('when false', function () { + it('should not send cache-control header', function (done) { + var app = express() + + app.use(function (req, res) { + res.sendFile(path.resolve(fixtures, 'user.html'), { + cacheControl: false + }) + }) + + request(app) + .get('/') + .expect(200) + .expect(utils.shouldNotHaveHeader('Cache-Control')) + .end(done) + }) + }) + }) + + describe('with "dotfiles" option', function () { + describe('when "allow"', function () { + it('should allow dotfiles', function (done) { + var app = express() + + app.use(function (req, res) { + res.sendFile(path.resolve(fixtures, '.name'), { + dotfiles: 'allow' + }) + }) + + request(app) + .get('/') + .expect(200) + .expect(utils.shouldHaveBody(Buffer.from('tobi'))) + .end(done) + }) + }) + + describe('when "deny"', function () { + it('should deny dotfiles', function (done) { + var app = express() + + app.use(function (req, res) { + res.sendFile(path.resolve(fixtures, '.name'), { + dotfiles: 'deny' + }) + }) + + request(app) + .get('/') + .expect(403) + .expect(/Forbidden/) + .end(done) + }) + }) + + describe('when "ignore"', function () { + it('should ignore dotfiles', function (done) { + var app = express() + + app.use(function (req, res) { + res.sendFile(path.resolve(fixtures, '.name'), { + dotfiles: 'ignore' + }) + }) + + request(app) + .get('/') + .expect(404) + .expect(/Not Found/) + .end(done) + }) + }) + }) + + describe('with "headers" option', function () { + it('should set headers on response', function (done) { + var app = express() + + app.use(function (req, res) { + res.sendFile(path.resolve(fixtures, 'user.html'), { + headers: { + 'X-Foo': 'Bar', + 'X-Bar': 'Foo' + } + }) + }) + + request(app) + .get('/') + .expect(200) + .expect('X-Foo', 'Bar') + .expect('X-Bar', 'Foo') + .end(done) + }) + + it('should use last header when duplicated', function (done) { + var app = express() + + app.use(function (req, res) { + res.sendFile(path.resolve(fixtures, 'user.html'), { + headers: { + 'X-Foo': 'Bar', + 'x-foo': 'bar' + } + }) + }) + + request(app) + .get('/') + .expect(200) + .expect('X-Foo', 'bar') + .end(done) + }) + + it('should override Content-Type', function (done) { + var app = express() + + app.use(function (req, res) { + res.sendFile(path.resolve(fixtures, 'user.html'), { + headers: { + 'Content-Type': 'text/x-custom' + } + }) + }) + + request(app) + .get('/') + .expect(200) + .expect('Content-Type', 'text/x-custom') + .end(done) + }) + + it('should not set headers on 404', function (done) { + var app = express() + + app.use(function (req, res) { + res.sendFile(path.resolve(fixtures, 'does-not-exist'), { + headers: { + 'X-Foo': 'Bar' + } + }) + }) + + request(app) + .get('/') + .expect(404) + .expect(utils.shouldNotHaveHeader('X-Foo')) + .end(done) + }) + }) + + describe('with "immutable" option', function () { + describe('when true', function () { + it('should send cache-control header with immutable', function (done) { + var app = express() + + app.use(function (req, res) { + res.sendFile(path.resolve(fixtures, 'user.html'), { + immutable: true + }) + }) + + request(app) + .get('/') + .expect(200) + .expect('Cache-Control', 'public, max-age=0, immutable') + .end(done) + }) + }) + + describe('when false', function () { + it('should not send cache-control header with immutable', function (done) { + var app = express() + + app.use(function (req, res) { + res.sendFile(path.resolve(fixtures, 'user.html'), { + immutable: false + }) + }) + + request(app) + .get('/') + .expect(200) + .expect('Cache-Control', 'public, max-age=0') + .end(done) + }) + }) + }) + + describe('with "lastModified" option', function () { + describe('when true', function () { + it('should send last-modified header', function (done) { + var app = express() + + app.use(function (req, res) { + res.sendFile(path.resolve(fixtures, 'user.html'), { + lastModified: true + }) + }) + + request(app) + .get('/') + .expect(200) + .expect(utils.shouldHaveHeader('Last-Modified')) + .end(done) + }) + + it('should conditionally respond with if-modified-since', function (done) { + var app = express() + + app.use(function (req, res) { + res.sendFile(path.resolve(fixtures, 'user.html'), { + lastModified: true + }) + }) + + request(app) + .get('/') + .set('If-Modified-Since', (new Date(Date.now() + 99999).toUTCString())) + .expect(304, done) + }) + }) + + describe('when false', function () { + it('should not have last-modified header', function (done) { + var app = express() + + app.use(function (req, res) { + res.sendFile(path.resolve(fixtures, 'user.html'), { + lastModified: false + }) + }) + + request(app) + .get('/') + .expect(200) + .expect(utils.shouldNotHaveHeader('Last-Modified')) + .end(done) + }) + + it('should not honor if-modified-since', function (done) { + var app = express() + + app.use(function (req, res) { + res.sendFile(path.resolve(fixtures, 'user.html'), { + lastModified: false + }) + }) + + request(app) + .get('/') + .set('If-Modified-Since', (new Date(Date.now() + 99999).toUTCString())) + .expect(200) + .expect(utils.shouldNotHaveHeader('Last-Modified')) + .end(done) + }) + }) + }) + + describe('with "maxAge" option', function () { + it('should set cache-control max-age to milliseconds', function (done) { + var app = express() + + app.use(function (req, res) { + res.sendFile(path.resolve(fixtures, 'user.html'), { + maxAge: 20000 + }) + }) + + request(app) + .get('/') + .expect(200) + .expect('Cache-Control', 'public, max-age=20') + .end(done) + }) + + it('should cap cache-control max-age to 1 year', function (done) { + var app = express() + + app.use(function (req, res) { + res.sendFile(path.resolve(fixtures, 'user.html'), { + maxAge: 99999999999 + }) + }) + + request(app) + .get('/') + .expect(200) + .expect('Cache-Control', 'public, max-age=31536000') + .end(done) + }) + + it('should min cache-control max-age to 0', function (done) { + var app = express() + + app.use(function (req, res) { + res.sendFile(path.resolve(fixtures, 'user.html'), { + maxAge: -20000 + }) + }) + + request(app) + .get('/') + .expect(200) + .expect('Cache-Control', 'public, max-age=0') + .end(done) + }) + + it('should floor cache-control max-age', function (done) { + var app = express() + + app.use(function (req, res) { + res.sendFile(path.resolve(fixtures, 'user.html'), { + maxAge: 21911.23 + }) + }) + + request(app) + .get('/') + .expect(200) + .expect('Cache-Control', 'public, max-age=21') + .end(done) + }) + + describe('when cacheControl: false', function () { + it('shold not send cache-control', function (done) { + var app = express() + + app.use(function (req, res) { + res.sendFile(path.resolve(fixtures, 'user.html'), { + cacheControl: false, + maxAge: 20000 + }) + }) + + request(app) + .get('/') + .expect(200) + .expect(utils.shouldNotHaveHeader('Cache-Control')) + .end(done) + }) + }) + + describe('when string', function () { + it('should accept plain number as milliseconds', function (done) { + var app = express() + + app.use(function (req, res) { + res.sendFile(path.resolve(fixtures, 'user.html'), { + maxAge: '20000' + }) + }) + + request(app) + .get('/') + .expect(200) + .expect('Cache-Control', 'public, max-age=20') + .end(done) + }) + + it('should accept suffix "s" for seconds', function (done) { + var app = express() + + app.use(function (req, res) { + res.sendFile(path.resolve(fixtures, 'user.html'), { + maxAge: '20s' + }) + }) + + request(app) + .get('/') + .expect(200) + .expect('Cache-Control', 'public, max-age=20') + .end(done) + }) + + it('should accept suffix "m" for minutes', function (done) { + var app = express() + + app.use(function (req, res) { + res.sendFile(path.resolve(fixtures, 'user.html'), { + maxAge: '20m' + }) + }) + + request(app) + .get('/') + .expect(200) + .expect('Cache-Control', 'public, max-age=1200') + .end(done) + }) + + it('should accept suffix "d" for days', function (done) { + var app = express() + + app.use(function (req, res) { + res.sendFile(path.resolve(fixtures, 'user.html'), { + maxAge: '20d' + }) + }) + + request(app) + .get('/') + .expect(200) + .expect('Cache-Control', 'public, max-age=1728000') + .end(done) + }) + }) + }) + + describe('with "root" option', function () { + it('should allow relative path', function (done) { + var app = express() + + app.use(function (req, res) { + res.sendFile('name.txt', { + root: fixtures + }) + }) + + request(app) + .get('/') + .expect(200, 'tobi', done) + }) + + it('should allow up within root', function (done) { + var app = express() + + app.use(function (req, res) { + res.sendFile('fake/../name.txt', { + root: fixtures + }) + }) + + request(app) + .get('/') + .expect(200, 'tobi', done) + }) + + it('should reject up outside root', function (done) { + var app = express() + + app.use(function (req, res) { + res.sendFile('..' + path.sep + path.relative(path.dirname(fixtures), path.join(fixtures, 'name.txt')), { + root: fixtures + }) + }) + + request(app) + .get('/') + .expect(403, done) + }) + + it('should reject reading outside root', function (done) { + var app = express() + + app.use(function (req, res) { + res.sendFile('../name.txt', { + root: fixtures + }) + }) + + request(app) + .get('/') + .expect(403, done) + }) + }) }) describe('.sendfile(path, fn)', function(){ diff --git a/test/support/utils.js b/test/support/utils.js index 579f042a0c..5b4062e0b2 100644 --- a/test/support/utils.js +++ b/test/support/utils.js @@ -13,6 +13,7 @@ var Buffer = require('safe-buffer').Buffer */ exports.shouldHaveBody = shouldHaveBody +exports.shouldHaveHeader = shouldHaveHeader exports.shouldNotHaveBody = shouldNotHaveBody exports.shouldNotHaveHeader = shouldNotHaveHeader; @@ -33,6 +34,19 @@ function shouldHaveBody (buf) { } } +/** + * Assert that a supertest response does have a header. + * + * @param {string} header Header name to check + * @returns {function} + */ + +function shouldHaveHeader (header) { + return function (res) { + assert.ok((header.toLowerCase() in res.headers), 'should have header ' + header) + } +} + /** * Assert that a supertest response does not have a body. * From 446046f886eb457c3d43f57c3f2fc97b698b317a Mon Sep 17 00:00:00 2001 From: Douglas Christopher Wilson Date: Tue, 1 Mar 2022 00:27:48 -0500 Subject: [PATCH 015/130] build: mocha@9.2.1 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 61e91899e6..7992166629 100644 --- a/package.json +++ b/package.json @@ -70,7 +70,7 @@ "hbs": "4.2.0", "marked": "0.7.0", "method-override": "3.0.0", - "mocha": "9.2.0", + "mocha": "9.2.1", "morgan": "1.10.0", "multiparty": "4.2.3", "nyc": "15.1.0", From 490f1a1738449699c217e00ba56db378923fd6b5 Mon Sep 17 00:00:00 2001 From: Tobias Speicher Date: Thu, 17 Mar 2022 13:00:48 +0100 Subject: [PATCH 016/130] lint: remove deprecated String.prototype.substr closes #4860 --- lib/router/index.js | 16 ++++++++-------- lib/view.js | 2 +- 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/lib/router/index.js b/lib/router/index.js index fbe94acdb4..467d30458c 100644 --- a/lib/router/index.js +++ b/lib/router/index.js @@ -108,8 +108,8 @@ proto.param = function param(name, fn) { var ret; if (name[0] === ':') { - deprecate('router.param(' + JSON.stringify(name) + ', fn): Use router.param(' + JSON.stringify(name.substr(1)) + ', fn) instead'); - name = name.substr(1); + deprecate('router.param(' + JSON.stringify(name) + ', fn): Use router.param(' + JSON.stringify(name.slice(1)) + ', fn) instead') + name = name.slice(1) } for (var i = 0; i < len; ++i) { @@ -180,14 +180,14 @@ proto.handle = function handle(req, res, out) { // remove added slash if (slashAdded) { - req.url = req.url.substr(1); + req.url = req.url.slice(1) slashAdded = false; } // restore altered req.url if (removed.length !== 0) { req.baseUrl = parentUrl; - req.url = protohost + removed + req.url.substr(protohost.length); + req.url = protohost + removed + req.url.slice(protohost.length) removed = ''; } @@ -288,7 +288,7 @@ proto.handle = function handle(req, res, out) { function trim_prefix(layer, layerError, layerPath, path) { if (layerPath.length !== 0) { // Validate path is a prefix match - if (layerPath !== path.substr(0, layerPath.length)) { + if (layerPath !== path.slice(0, layerPath.length)) { next(layerError) return } @@ -301,7 +301,7 @@ proto.handle = function handle(req, res, out) { // middleware (.use stuff) needs to have the path stripped debug('trim prefix (%s) from url %s', layerPath, req.url); removed = layerPath; - req.url = protohost + req.url.substr(protohost.length + removed.length); + req.url = protohost + req.url.slice(protohost.length + removed.length) // Ensure leading slash if (!protohost && req.url[0] !== '/') { @@ -547,10 +547,10 @@ function getProtohost(url) { var pathLength = searchIndex !== -1 ? searchIndex : url.length - var fqdnIndex = url.substr(0, pathLength).indexOf('://') + var fqdnIndex = url.slice(0, pathLength).indexOf('://') return fqdnIndex !== -1 - ? url.substr(0, url.indexOf('/', 3 + fqdnIndex)) + ? url.substring(0, url.indexOf('/', 3 + fqdnIndex)) : undefined } diff --git a/lib/view.js b/lib/view.js index cf101caeab..c08ab4d8d5 100644 --- a/lib/view.js +++ b/lib/view.js @@ -74,7 +74,7 @@ function View(name, options) { if (!opts.engines[this.ext]) { // load engine - var mod = this.ext.substr(1) + var mod = this.ext.slice(1) debug('require "%s"', mod) // default engine export From 2a7417dd84025b62c4207bf018ae8826dc0be629 Mon Sep 17 00:00:00 2001 From: Hashen <37979557+Hashen110@users.noreply.github.com> Date: Sun, 20 Mar 2022 19:58:13 +0530 Subject: [PATCH 017/130] examples: fixup html closes #4866 --- examples/route-separation/views/users/edit.ejs | 2 +- examples/search/public/index.html | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/examples/route-separation/views/users/edit.ejs b/examples/route-separation/views/users/edit.ejs index 0ca2df7652..6df78a953a 100644 --- a/examples/route-separation/views/users/edit.ejs +++ b/examples/route-separation/views/users/edit.ejs @@ -3,7 +3,7 @@

Editing <%= user.name %>

-
+

Name: diff --git a/examples/search/public/index.html b/examples/search/public/index.html index f67063c502..7353644ba6 100644 --- a/examples/search/public/index.html +++ b/examples/search/public/index.html @@ -4,7 +4,7 @@ Search example -