Skimless.
packet 156b30e9 · 2026-09-23 07:31 · story

Review packet

Do not skim this one

65 files · +1115 −3441 · about 114 min. 5 high-priority findings. First pass: index.js, app.del.js, req.acceptsCharset.js.

65files
+1115added
−3441removed
114min
100high

Reading order

  1. 01 lib/router/index.js
    Public export changed
    Then this
  2. 02 test/app.del.js
    Test file deleted
    Read now
  3. 03 test/req.acceptsCharset.js
    Test file deleted
    Read now
  4. 04 test/req.acceptsEncoding.js
    Test file deleted
    Read now
  5. 05 test/req.acceptsLanguage.js
    Test file deleted
    Read now
  6. 06 test/req.param.js
    Test file deleted
    Read now
  7. 07 .github/workflows/ci.yml
    Automation changed
    Can wait
  8. 08 .github/workflows/iojs.yml
    Automation changed
    Can wait
  9. 09 .github/workflows/legacy.yml
    Automation changed
    Can wait
  10. 10 appveyor.yml
    Automation changed
    Can wait
  11. 11 package.json
    Dependency manifest changed
    Then this
  12. 12 lib/view.js
    Behavior changed without a matching test
    Then this
  13. 13 .eslintrc.yml
    Implementation
    Can wait
  14. 14 lib/application.js
    Implementation
    Can wait
  15. 15 lib/express.js
    Implementation
    Can wait
  16. 16 lib/middleware/init.js
    Implementation
    Can wait
  17. 17 lib/middleware/query.js
    Implementation
    Can wait
  18. 18 lib/request.js
    Implementation
    Can wait
  19. 19 lib/response.js
    Implementation
    Can wait
  20. 20 lib/router/layer.js
    Implementation
    Can wait
  21. 21 lib/router/route.js
    Implementation
    Can wait
  22. 22 lib/utils.js
    Implementation
    Can wait
  23. 23 test/app.router.js
    Large file in the diff
    Then this
  24. 24 test/res.sendFile.js
    Large file in the diff
    Then this
  25. 25 test/app.all.js
    Tests
    Can wait
  26. 26 test/app.js
    Tests
    Can wait
  27. 27 test/app.listen.js
    Tests
    Can wait
  28. 28 test/app.locals.js
    Tests
    Can wait
  29. 29 test/app.options.js
    Tests
    Can wait
  30. 30 test/app.param.js
    Tests
    Can wait
  31. 31 test/app.route.js
    Tests
    Can wait
  32. 32 test/app.routes.error.js
    Tests
    Can wait
  33. 33 test/app.use.js
    Tests
    Can wait
  34. 34 test/exports.js
    Tests
    Can wait
  35. 35 test/express.json.js
    Tests
    Can wait
  36. 36 test/express.raw.js
    Tests
    Can wait
  37. 37 test/express.static.js
    Tests
    Can wait
  38. 38 test/express.text.js
    Tests
    Can wait
  39. 39 test/express.urlencoded.js
    Tests
    Can wait
  40. 40 test/req.fresh.js
    Tests
    Can wait
  41. 41 test/req.host.js
    Tests
    Can wait
  42. 42 test/req.query.js
    Tests
    Can wait
  43. 43 test/req.route.js
    Tests
    Can wait
  44. 44 test/res.clearCookie.js
    Tests
    Can wait
  45. 45 test/res.download.js
    Tests
    Can wait
  46. 46 test/res.format.js
    Tests
    Can wait
  47. 47 test/res.json.js
    Tests
    Can wait
  48. 48 test/res.jsonp.js
    Tests
    Can wait
  49. 49 test/res.location.js
    Tests
    Can wait
  50. 50 test/res.redirect.js
    Tests
    Can wait
  51. 51 test/res.send.js
    Tests
    Can wait
  52. 52 test/res.sendStatus.js
    Tests
    Can wait
  53. 53 test/res.status.js
    Tests
    Can wait
  54. 54 test/res.type.js
    Tests
    Can wait
  55. 55 test/res.vary.js
    Tests
    Can wait
  56. 56 test/Router.js
    Tests
    Can wait
  57. 57 test/utils.js
    Tests
    Can wait
  58. 58 examples/auth/index.js
    Docs
    Can wait
  59. 59 examples/cookies/index.js
    Docs
    Can wait
  60. 60 examples/downloads/index.js
    Docs
    Can wait
  61. 61 examples/resource/index.js
    Docs
    Can wait
  62. 62 examples/route-separation/index.js
    Docs
    Can wait
  63. 63 examples/route-separation/user.js
    Docs
    Can wait
  64. 64 examples/search/index.js
    Docs
    Can wait
  65. 65 History.md
    Docs
    Can wait

Findings

high
Test file deleted
test/app.del.js

Deleted coverage does not come back on its own. Check the replacement test, or the reason there isn't one.

high
Test file deleted
test/req.acceptsCharset.js

Deleted coverage does not come back on its own. Check the replacement test, or the reason there isn't one.

high
Test file deleted
test/req.acceptsEncoding.js

Deleted coverage does not come back on its own. Check the replacement test, or the reason there isn't one.

high
Test file deleted
test/req.acceptsLanguage.js

Deleted coverage does not come back on its own. Check the replacement test, or the reason there isn't one.

high
Test file deleted
test/req.param.js

Deleted coverage does not come back on its own. Check the replacement test, or the reason there isn't one.

medium
Behavior changed without a matching test
lib/view.js

Nothing in this diff covers “view”. If the change is pure wiring, say so in the pull request.

medium
Dependency manifest changed
package.json

Read the new range here. The lockfile, later in the packet, is the resolved pin.

medium
Public export changed
lib/router/index.js

This is the contract other callers will see. Read it before the implementation that backs it.

medium
Large file in the diff
lib/router/index.js

673 changed lines. If it mixes two concerns, ask for a split.

medium
Large file in the diff
test/app.router.js

430 changed lines. If it mixes two concerns, ask for a split.

medium
Large file in the diff
test/res.sendFile.js

505 changed lines. If it mixes two concerns, ask for a split.

low
Automation changed
.github/workflows/ci.yml

No new write permission stood out. Still read which trigger and which secrets the job can see.

low
Automation changed
.github/workflows/iojs.yml

No new write permission stood out. Still read which trigger and which secrets the job can see.

low
Automation changed
.github/workflows/legacy.yml

No new write permission stood out. Still read which trigger and which secrets the job can see.

low
Automation changed
appveyor.yml

No new write permission stood out. Still read which trigger and which secrets the job can see.

Files

lib/router/index.js

deleted · Public API · +0 −673 · medium 16

medium Public export changed. This is the contract other callers will see. Read it before the implementation that backs it.

medium Large file in the diff. 673 changed lines. If it mixes two concerns, ask for a split.

@@ -1,673 +0,0 @@
1−/*!
2− * express
3− * Copyright(c) 2009-2013 TJ Holowaychuk
4− * Copyright(c) 2013 Roman Shtylman
5− * Copyright(c) 2014-2015 Douglas Christopher Wilson
6− * MIT Licensed
7− */
8
9−'use strict';
10
11−/**
12− * Module dependencies.
13− * @private
14− */
15
16−var Route = require('./route');
17−var Layer = require('./layer');
18−var methods = require('methods');
19−var mixin = require('utils-merge');
20−var debug = require('debug')('express:router');
21−var deprecate = require('depd')('express');
22−var flatten = require('array-flatten');
23−var parseUrl = require('parseurl');
24−var setPrototypeOf = require('setprototypeof')
25
26−/**
27− * Module variables.
28− * @private
29− */
30
31−var objectRegExp = /^\[object (\S+)\]$/;
32−var slice = Array.prototype.slice;
33−var toString = Object.prototype.toString;
34
35−/**
36− * Initialize a new `Router` with the given `options`.
37− *
38− * @param {Object} [options]
39− * @return {Router} which is a callable function
40− * @public
41− */
42
43−var proto = module.exports = function(options) {
44− var opts = options || {};
45
46− function router(req, res, next) {
47− router.handle(req, res, next);
48− }
49
50− // mixin Router class functions
51− setPrototypeOf(router, proto)
52
53− router.params = {};
54− router._params = [];
55− router.caseSensitive = opts.caseSensitive;
56− router.mergeParams = opts.mergeParams;
57− router.strict = opts.strict;
58− router.stack = [];
59
60− return router;
61−};
62
63−/**
64− * Map the given param placeholder `name`(s) to the given callback.
65− *
66− * Parameter mapping is used to provide pre-conditions to routes
67− * which use normalized placeholders. For example a _:user_id_ parameter
68− * could automatically load a user's information from the database without
69− * any additional code,
70− *
71− * The callback uses the same signature as middleware, the only difference
72− * being that the value of the placeholder is passed, in this case the _id_
73− * of the user. Once the `next()` function is invoked, just like middleware
74− * it will continue on to execute the route, or subsequent parameter functions.
75− *
76− * Just like in middleware, you must either respond to the request or call next
77− * to avoid stalling the request.
78− *
79− * app.param('user_id', function(req, res, next, id){
80− * User.find(id, function(err, user){
First 80 lines.

test/app.del.js

deleted · Tests · +0 −18 · high 26

high Test file deleted. Deleted coverage does not come back on its own. Check the replacement test, or the reason there isn't one.

@@ -1,18 +0,0 @@
1−'use strict'
2
3−var express = require('../')
4− , request = require('supertest');
5
6−describe('app.del()', function(){
7− it('should alias app.delete()', function(done){
8− var app = express();
9
10− app.del('/tobi', function(req, res){
11− res.end('deleted tobi!');
12− });
13
14− request(app)
15− .del('/tobi')
16− .expect('deleted tobi!', done);
17− })
18−})

test/req.acceptsCharset.js

deleted · Tests · +0 −50 · high 26

high Test file deleted. Deleted coverage does not come back on its own. Check the replacement test, or the reason there isn't one.

@@ -1,50 +0,0 @@
1−'use strict'
2
3−var express = require('../')
4− , request = require('supertest');
5
6−describe('req', function(){
7− describe('.acceptsCharset(type)', function(){
8− describe('when Accept-Charset is not present', function(){
9− it('should return true', function(done){
10− var app = express();
11
12− app.use(function(req, res, next){
13− res.end(req.acceptsCharset('utf-8') ? 'yes' : 'no');
14− });
15
16− request(app)
17− .get('/')
18− .expect('yes', done);
19− })
20− })
21
22− describe('when Accept-Charset is present', function () {
23− it('should return true', function (done) {
24− var app = express();
25
26− app.use(function(req, res, next){
27− res.end(req.acceptsCharset('utf-8') ? 'yes' : 'no');
28− });
29
30− request(app)
31− .get('/')
32− .set('Accept-Charset', 'foo, bar, utf-8')
33− .expect('yes', done);
34− })
35
36− it('should return false otherwise', function(done){
37− var app = express();
38
39− app.use(function(req, res, next){
40− res.end(req.acceptsCharset('utf-8') ? 'yes' : 'no');
41− });
42
43− request(app)
44− .get('/')
45− .set('Accept-Charset', 'foo, bar')
46− .expect('no', done);
47− })
48− })
49− })
50−})

test/req.acceptsEncoding.js

deleted · Tests · +0 −39 · high 26

high Test file deleted. Deleted coverage does not come back on its own. Check the replacement test, or the reason there isn't one.

@@ -1,39 +0,0 @@
1−'use strict'
2
3−var express = require('../')
4− , request = require('supertest');
5
6−describe('req', function(){
7− describe('.acceptsEncoding', function(){
8− it('should return encoding if accepted', function (done) {
9− var app = express();
10
11− app.get('/', function (req, res) {
12− res.send({
13− gzip: req.acceptsEncoding('gzip'),
14− deflate: req.acceptsEncoding('deflate')
15− })
16− })
17
18− request(app)
19− .get('/')
20− .set('Accept-Encoding', ' gzip, deflate')
21− .expect(200, { gzip: 'gzip', deflate: 'deflate' }, done)
22− })
23
24− it('should be false if encoding not accepted', function(done){
25− var app = express();
26
27− app.get('/', function (req, res) {
28− res.send({
29− bogus: req.acceptsEncoding('bogus')
30− })
31− })
32
33− request(app)
34− .get('/')
35− .set('Accept-Encoding', ' gzip, deflate')
36− .expect(200, { bogus: false }, done)
37− })
38− })
39−})

test/req.acceptsLanguage.js

deleted · Tests · +0 −57 · high 26

high Test file deleted. Deleted coverage does not come back on its own. Check the replacement test, or the reason there isn't one.

@@ -1,57 +0,0 @@
1−'use strict'
2
3−var express = require('../')
4− , request = require('supertest');
5
6−describe('req', function(){
7− describe('.acceptsLanguage', function(){
8− it('should return language if accepted', function (done) {
9− var app = express();
10
11− app.get('/', function (req, res) {
12− res.send({
13− 'en-us': req.acceptsLanguage('en-us'),
14− en: req.acceptsLanguage('en')
15− })
16− })
17
18− request(app)
19− .get('/')
20− .set('Accept-Language', 'en;q=.5, en-us')
21− .expect(200, { 'en-us': 'en-us', en: 'en' }, done)
22− })
23
24− it('should be false if language not accepted', function(done){
25− var app = express();
26
27− app.get('/', function (req, res) {
28− res.send({
29− es: req.acceptsLanguage('es')
30− })
31− })
32
33− request(app)
34− .get('/')
35− .set('Accept-Language', 'en;q=.5, en-us')
36− .expect(200, { es: false }, done)
37− })
38
39− describe('when Accept-Language is not present', function(){
40− it('should always return language', function (done) {
41− var app = express();
42
43− app.get('/', function (req, res) {
44− res.send({
45− en: req.acceptsLanguage('en'),
46− es: req.acceptsLanguage('es'),
47− jp: req.acceptsLanguage('jp')
48− })
49− })
50
51− request(app)
52− .get('/')
53− .expect(200, { en: 'en', es: 'es', jp: 'jp' }, done)
54− })
55− })
56− })
57−})

test/req.param.js

deleted · Tests · +0 −61 · high 26

high Test file deleted. Deleted coverage does not come back on its own. Check the replacement test, or the reason there isn't one.

@@ -1,61 +0,0 @@
1−'use strict'
2
3−var express = require('../')
4− , request = require('supertest')
5
6−describe('req', function(){
7− describe('.param(name, default)', function(){
8− it('should use the default value unless defined', function(done){
9− var app = express();
10
11− app.use(function(req, res){
12− res.end(req.param('name', 'tj'));
13− });
14
15− request(app)
16− .get('/')
17− .expect('tj', done);
18− })
19− })
20
21− describe('.param(name)', function(){
22− it('should check req.query', function(done){
23− var app = express();
24
25− app.use(function(req, res){
26− res.end(req.param('name'));
27− });
28
29− request(app)
30− .get('/?name=tj')
31− .expect('tj', done);
32− })
33
34− it('should check req.body', function(done){
35− var app = express();
36
37− app.use(express.json())
38
39− app.use(function(req, res){
40− res.end(req.param('name'));
41− });
42
43− request(app)
44− .post('/')
45− .send({ name: 'tj' })
46− .expect('tj', done);
47− })
48
49− it('should check req.params', function(done){
50− var app = express();
51
52− app.get('/user/:name', function(req, res){
53− res.end(req.param('filter') + req.param('name'));
54− });
55
56− request(app)
57− .get('/user/tj')
58− .expect('undefinedtj', done);
59− })
60− })
61−})

.github/workflows/ci.yml

modified · Automation · +5 −78 · low 4

low Automation changed. No new write permission stood out. Still read which trigger and which secrets the job can see.

@@ -7,6 +7,7 @@ on:
7 - develop
8 - '4.x'
9 - '5.x'
10+ - '5.0'
11 paths-ignore:
12 - '*.md'
13 pull_request:
@@ -38,77 +39,14 @@ jobs:
39 run: npm run lint
40
41 test:
41− name: Run tests
42 strategy:
43 fail-fast: false
44 matrix:
45 os: [ubuntu-latest, windows-latest]
46− node-version:
47− - "0.10"
48− - "0.12"
49− - "4"
50− - "5"
51− - "6"
52− - "7"
53− - "8"
54− - "9"
55− - "10"
56− - "11"
57− - "12"
58− - "13"
59− - "14"
60− - "15"
61− - "16"
62− - "17"
63− - "18"
64− - "19"
65− - "20"
66− - "21"
67− - "22"
68− # Use supported versions of our testing tools under older versions of Node
69− # Install npm in some specific cases where we need to
70− include:
71− - node-version: "0.10"
72− npm-i: "mocha@3.5.3 nyc@10.3.2 supertest@2.0.0"
73− # Npm isn't being installed on windows w/ setup-node for
74− # 0.10 and 0.12, which will end up choking when npm uses es6
75− npm-version: "npm@2.15.1"
76
77− - node-version: "0.12"
78− npm-i: "mocha@3.5.3 nyc@10.3.2 supertest@2.0.0"
79− npm-version: "npm@2.15.11"
80
81− - node-version: "4"
82− npm-i: "mocha@5.2.0 nyc@11.9.0 supertest@3.4.2"
83
84− - node-version: "5"
85− npm-i: "mocha@5.2.0 nyc@11.9.0 supertest@3.4.2"
86− # fixes https://github.com/npm/cli/issues/681
87− npm-version: "npm@3.10.10"
88
89− - node-version: "6"
90− npm-i: "mocha@6.2.2 nyc@14.1.1 supertest@3.4.2"
91
92− - node-version: "7"
93− npm-i: "mocha@6.2.2 nyc@14.1.1 supertest@6.1.6"
94
95− - node-version: "8"
96− npm-i: "mocha@7.2.0 nyc@14.1.1"
97
98− - node-version: "9"
99− npm-i: "mocha@7.2.0 nyc@14.1.1"
100
101− - node-version: "10"
102− npm-i: "mocha@8.4.0"
103
104− - node-version: "11"
105− npm-i: "mocha@8.4.0"
106
107− - node-version: "12"
108− npm-i: "mocha@9.2.2"
109
110− - node-version: "13"
First 80 lines.

.github/workflows/iojs.yml

deleted · Automation · +0 −69 · low 4

low Automation changed. No new write permission stood out. Still read which trigger and which secrets the job can see.

@@ -1,69 +0,0 @@
1−name: iojs-ci
2
3−on:
4− push:
5− branches:
6− - master
7− - '4.x'
8− paths-ignore:
9− - '*.md'
10− pull_request:
11− paths-ignore:
12− - '*.md'
13
14−concurrency:
15− group: "${{ github.workflow }} ✨ ${{ github.event.pull_request.head.label || github.head_ref || github.ref }}"
16− cancel-in-progress: true
17
18−jobs:
19− test:
20− runs-on: ubuntu-latest
21− strategy:
22− fail-fast: false
23− matrix:
24− node-version: ["1.8", "2.5", "3.3"]
25− include:
26− - node-version: "1.8"
27− npm-i: "mocha@3.5.3 nyc@10.3.2 supertest@2.0.0"
28− - node-version: "2.5"
29− npm-i: "mocha@3.5.3 nyc@10.3.2 supertest@2.0.0"
30− - node-version: "3.3"
31− npm-i: "mocha@3.5.3 nyc@10.3.2 supertest@2.0.0"
32
33− steps:
34− - uses: actions/checkout@v4
35
36− - name: Install iojs ${{ matrix.node-version }}
37− shell: bash -eo pipefail -l {0}
38− run: |
39− nvm install --default ${{ matrix.node-version }}
40− dirname "$(nvm which ${{ matrix.node-version }})" >> "$GITHUB_PATH"
41
42− - name: Configure npm
43− run: |
44− npm config set loglevel error
45− npm config set shrinkwrap false
46
47− - name: Install npm module(s) ${{ matrix.npm-i }}
48− run: npm install --save-dev ${{ matrix.npm-i }}
49− if: matrix.npm-i != ''
50
51− - name: Remove non-test dependencies
52− run: npm rm --silent --save-dev connect-redis
53
54− - name: Install Node.js dependencies
55− run: npm install
56
57− - name: List environment
58− id: list_env
59− shell: bash
60− run: |
61− echo "node@$(node -v)"
62− echo "npm@$(npm -v)"
63− npm -s ls ||:
64− (npm -s ls --depth=0 ||:) | awk -F'[ @]' 'NR>1 && $2 { print $2 "=" $3 }' >> "$GITHUB_OUTPUT"
65
66− - name: Run tests
67− shell: bash
68− run: npm run test
69

.github/workflows/legacy.yml

added · Automation · +100 −0 · low 4

low Automation changed. No new write permission stood out. Still read which trigger and which secrets the job can see.

@@ -0,0 +1,100 @@
1+name: legacy
2+
3+on:
4+ push:
5+ branches:
6+ - master
7+ - develop
8+ - '4.x'
9+ - '5.x'
10+ - '5.0'
11+ paths-ignore:
12+ - '*.md'
13+ pull_request:
14+ paths-ignore:
15+ - '*.md'
16+
17+# Cancel in progress workflows
18+# in the scenario where we already had a run going for that PR/branch/tag but then triggered a new run
19+concurrency:
20+ group: "${{ github.workflow }} ✨ ${{ github.event.pull_request.head.label || github.head_ref || github.ref }}"
21+ cancel-in-progress: true
22+
23+jobs:
24+ test:
25+ strategy:
26+ fail-fast: false
27+ matrix:
28+ os: [ubuntu-latest, windows-latest]
29+ node-version: [16, 17]
30+ # Node.js release schedule: https://nodejs.org/en/about/releases/
31+
32+ name: Node.js ${{ matrix.node-version }} - ${{matrix.os}}
33+
34+ runs-on: ${{ matrix.os }}
35+ steps:
36+ - uses: actions/checkout@v4
37+ with:
38+ persist-credentials: false
39+
40+ - name: Setup Node.js ${{ matrix.node-version }}
41+ uses: actions/setup-node@v4
42+ with:
43+ node-version: ${{ matrix.node-version }}
44+
45+ - name: Configure npm loglevel
46+ run: |
47+ npm config set loglevel error
48+ shell: bash
49+
50+ - name: Install dependencies
51+ run: npm install
52+
53+ - name: Output Node and NPM versions
54+ run: |
55+ echo "Node.js version: $(node -v)"
56+ echo "NPM version: $(npm -v)"
57+
58+ - name: Run tests
59+ shell: bash
60+ run: |
61+ npm run test-ci
62+ cp coverage/lcov.info "coverage/${{ matrix.node-version }}.lcov"
63+
64+ - name: Collect code coverage
65+ run: |
66+ mv ./coverage "./${{ matrix.node-version }}"
67+ mkdir ./coverage
68+ mv "./${{ matrix.node-version }}" "./coverage/${{ matrix.node-version }}"
69+
70+ - name: Upload code coverage
71+ uses: actions/upload-artifact@v3
72+ with:
73+ name: coverage
74+ path: ./coverage
75+ retention-days: 1
76+
77+ coverage:
78+ needs: test
79+ runs-on: ubuntu-latest
80+ steps:
First 80 lines.

appveyor.yml

deleted · Automation · +0 −113 · low 4

low Automation changed. No new write permission stood out. Still read which trigger and which secrets the job can see.

@@ -1,113 +0,0 @@
1−environment:
2− matrix:
3− - nodejs_version: "0.10"
4− - nodejs_version: "0.12"
5− - nodejs_version: "1.8"
6− - nodejs_version: "2.5"
7− - nodejs_version: "3.3"
8− - nodejs_version: "4.9"
9− - nodejs_version: "5.12"
10− - nodejs_version: "6.17"
11− - nodejs_version: "7.10"
12− - nodejs_version: "8.17"
13− - nodejs_version: "9.11"
14− - nodejs_version: "10.24"
15− - nodejs_version: "11.15"
16− - nodejs_version: "12.22"
17− - nodejs_version: "13.14"
18− - nodejs_version: "14.20"
19− - nodejs_version: "15.14"
20− - nodejs_version: "16.20"
21− - nodejs_version: "17.9"
22− - nodejs_version: "18.19"
23− - nodejs_version: "19.9"
24− - nodejs_version: "20.11"
25− - nodejs_version: "21.6"
26− - nodejs_version: "22.0"
27−cache:
28− - node_modules
29−install:
30− # Install Node.js
31− - ps: >-
32− try { Install-Product node $env:nodejs_version -ErrorAction Stop }
33− catch { Update-NodeJsInstallation (Get-NodeJsLatestBuild $env:nodejs_version) x64 }
34− # Configure npm
35− - ps: |
36− npm config set loglevel error
37− if ((npm config get package-lock) -eq "true") {
38− npm config set package-lock false
39− } else {
40− npm config set shrinkwrap false
41− }
42− # Remove all non-test dependencies
43− - ps: |
44− # Remove example dependencies
45− npm rm --silent --save-dev connect-redis
46− # Remove lint dependencies
47− cmd.exe /c "node -pe `"Object.keys(require('./package').devDependencies).join('\n')`"" | `
48− sls "^eslint(-|$)" | `
49− %{ npm rm --silent --save-dev $_ }
50− # Setup Node.js version-specific dependencies
51− - ps: |
52− # mocha for testing
53− # - use 3.x for Node.js < 4
54− # - use 5.x for Node.js < 6
55− # - use 6.x for Node.js < 8
56− # - use 7.x for Node.js < 10
57− # - use 8.x for Node.js < 12
58− # - use 9.x for Node.js < 14
59− if ([int]$env:nodejs_version.split(".")[0] -lt 4) {
60− npm install --silent --save-dev mocha@3.5.3
61− } elseif ([int]$env:nodejs_version.split(".")[0] -lt 6) {
62− npm install --silent --save-dev mocha@5.2.0
63− } elseif ([int]$env:nodejs_version.split(".")[0] -lt 8) {
64− npm install --silent --save-dev mocha@6.2.2
65− } elseif ([int]$env:nodejs_version.split(".")[0] -lt 10) {
66− npm install --silent --save-dev mocha@7.2.0
67− } elseif ([int]$env:nodejs_version.split(".")[0] -lt 12) {
68− npm install --silent --save-dev mocha@8.4.0
69− } elseif ([int]$env:nodejs_version.split(".")[0] -lt 14) {
70− npm install --silent --save-dev mocha@9.2.2
71− }
72− - ps: |
73− # nyc for test coverage
74− # - use 10.3.2 for Node.js < 4
75− # - use 11.9.0 for Node.js < 6
76− # - use 14.1.1 for Node.js < 10
77− if ([int]$env:nodejs_version.split(".")[0] -lt 4) {
78− npm install --silent --save-dev nyc@10.3.2
79− } elseif ([int]$env:nodejs_version.split(".")[0] -lt 6) {
80− npm install --silent --save-dev nyc@11.9.0
First 80 lines.

package.json

modified · Dependencies · +17 −20 · medium 10

medium Dependency manifest changed. Read the new range here. The lockfile, later in the packet, is the resolved pin.

@@ -1,7 +1,7 @@
1 {
2 "name": "express",
3 "description": "Fast, unopinionated, minimalist web framework",
4− "version": "4.21.2",
4+ "version": "5.0.0",
5 "author": "TJ Holowaychuk <tj@vision-media.ca>",
6 "contributors": [
7 "Aaron Heckmann <aaron.heckmann+github@gmail.com>",
@@ -15,10 +15,6 @@
15 "license": "MIT",
16 "repository": "expressjs/express",
17 "homepage": "http://expressjs.com/",
18− "funding": {
19− "type": "opencollective",
20− "url": "https://opencollective.com/express"
21− },
18 "keywords": [
19 "express",
20 "framework",
@@ -32,35 +28,36 @@
28 "api"
29 ],
30 "dependencies": {
35− "accepts": "~1.3.8",
36− "array-flatten": "1.1.1",
37− "body-parser": "1.20.3",
38− "content-disposition": "0.5.4",
31+ "accepts": "^2.0.0",
32+ "body-parser": "^2.0.1",
33+ "content-disposition": "^1.0.0",
34 "content-type": "~1.0.4",
40− "cookie": "0.7.1",
41− "cookie-signature": "1.0.6",
42− "debug": "2.6.9",
35+ "cookie": "0.6.0",
36+ "cookie-signature": "^1.2.1",
37+ "debug": "4.3.6",
38 "depd": "2.0.0",
39 "encodeurl": "~2.0.0",
40 "escape-html": "~1.0.3",
41 "etag": "~1.8.1",
47− "finalhandler": "1.3.1",
48− "fresh": "0.5.2",
42+ "finalhandler": "^2.0.0",
43+ "fresh": "2.0.0",
44 "http-errors": "2.0.0",
50− "merge-descriptors": "1.0.3",
45+ "merge-descriptors": "^2.0.0",
46 "methods": "~1.1.2",
47+ "mime-types": "^3.0.0",
48 "on-finished": "2.4.1",
49+ "once": "1.4.0",
50 "parseurl": "~1.3.3",
54− "path-to-regexp": "0.1.12",
51 "proxy-addr": "~2.0.7",
52 "qs": "6.13.0",
53 "range-parser": "~1.2.1",
54+ "router": "^2.0.0",
55 "safe-buffer": "5.2.1",
59− "send": "0.19.0",
60− "serve-static": "1.16.2",
56+ "send": "^1.1.0",
57+ "serve-static": "^2.1.0",
58 "setprototypeof": "1.2.0",
59 "statuses": "2.0.1",
63− "type-is": "~1.6.18",
60+ "type-is": "^2.0.0",
61 "utils-merge": "1.0.1",
62 "vary": "~1.1.2"
63 },
@@ -83,7 +80,7 @@
80 "vhost": "~3.0.2"
81 },
82 "engines": {
86− "node": ">= 0.10.0"
83+ "node": ">= 18"
84 },
85 "files": [
86 "LICENSE",

lib/view.js

modified · Implementation · +24 −1 · medium 12

medium Behavior changed without a matching test. Nothing in this diff covers “view”. If the change is pure wiring, say so in the pull request.

@@ -131,8 +131,31 @@ View.prototype.lookup = function lookup(name) {
131 */
132
133 View.prototype.render = function render(options, callback) {
134+ var sync = true;
135+
136 debug('render "%s"', this.path);
135− this.engine(this.path, options, callback);
137+
138+ // render, normalizing sync callbacks
139+ this.engine(this.path, options, function onRender() {
140+ if (!sync) {
141+ return callback.apply(this, arguments);
142+ }
143+
144+ // copy arguments
145+ var args = new Array(arguments.length);
146+ var cntx = this;
147+
148+ for (var i = 0; i < arguments.length; i++) {
149+ args[i] = arguments[i];
150+ }
151+
152+ // force callback to be async
153+ return process.nextTick(function renderTick() {
154+ return callback.apply(cntx, args);
155+ });
156+ });
157+
158+ sync = false;
159 };
160
161 /**

.eslintrc.yml

modified · Implementation · +3 −1 · calm 0
@@ -1,5 +1,7 @@
1 root: true
2
2+env:
3+ es2022: true
4+ node: true
5 rules:
6 eol-last: error
7 eqeqeq: [error, allow-null]

lib/application.js

modified · Implementation · +59 −78 · calm 0
@@ -14,20 +14,17 @@
14 */
15
16 var finalhandler = require('finalhandler');
17−var Router = require('./router');
17 var methods = require('methods');
19−var middleware = require('./middleware/init');
20−var query = require('./middleware/query');
18 var debug = require('debug')('express:application');
19 var View = require('./view');
20 var http = require('http');
21 var compileETag = require('./utils').compileETag;
22 var compileQueryParser = require('./utils').compileQueryParser;
23 var compileTrust = require('./utils').compileTrust;
27−var deprecate = require('depd')('express');
28−var flatten = require('array-flatten');
24 var merge = require('utils-merge');
25 var resolve = require('path').resolve;
26+var once = require('once')
27+var Router = require('router');
28 var setPrototypeOf = require('setprototypeof')
29
30 /**
@@ -35,8 +32,8 @@ var setPrototypeOf = require('setprototypeof')
32 * @private
33 */
34
38−var hasOwnProperty = Object.prototype.hasOwnProperty
35 var slice = Array.prototype.slice;
36+var flatten = Array.prototype.flat;
37
38 /**
39 * Application prototype.
@@ -62,11 +59,29 @@ var trustProxyDefaultSymbol = '@@symbol:trust_proxy_default';
59 */
60
61 app.init = function init() {
65− this.cache = {};
66− this.engines = {};
67− this.settings = {};
62+ var router = null;
63+
64+ this.cache = Object.create(null);
65+ this.engines = Object.create(null);
66+ this.settings = Object.create(null);
67
68 this.defaultConfiguration();
69+
70+ // Setup getting to lazily add base router
71+ Object.defineProperty(this, 'router', {
72+ configurable: true,
73+ enumerable: true,
74+ get: function getrouter() {
75+ if (router === null) {
76+ router = new Router({
77+ caseSensitive: this.enabled('case sensitive routing'),
78+ strict: this.enabled('strict routing')
79+ });
80+ }
81+
82+ return router;
83+ }
84+ });
85 };
86
87 /**
@@ -81,7 +96,7 @@ app.defaultConfiguration = function defaultConfiguration() {
96 this.enable('x-powered-by');
97 this.set('etag', 'weak');
98 this.set('env', env);
84− this.set('query parser', 'extended');
99+ this.set('query parser', 'simple')
100 this.set('subdomain offset', 2);
101 this.set('trust proxy', false);
102
@@ -125,32 +140,6 @@ app.defaultConfiguration = function defaultConfiguration() {
140 if (env === 'production') {
141 this.enable('view cache');
142 }
128
129− Object.defineProperty(this, 'router', {
130− get: function() {
131− throw new Error('\'app.router\' is deprecated!\nPlease see the 3.x to 4.x migration guide for details on how to update your app.');
132− }
133− });
First 80 lines.

lib/express.js

modified · Implementation · +2 −37 · calm 0
@@ -16,8 +16,7 @@ var bodyParser = require('body-parser')
16 var EventEmitter = require('events').EventEmitter;
17 var mixin = require('merge-descriptors');
18 var proto = require('./application');
19−var Route = require('./router/route');
20−var Router = require('./router');
19+var Router = require('router');
20 var req = require('./request');
21 var res = require('./response');
22
@@ -68,7 +67,7 @@ exports.response = res;
67 * Expose constructors.
68 */
69
71−exports.Route = Route;
70+exports.Route = Router.Route;
71 exports.Router = Router;
72
73 /**
@@ -76,41 +75,7 @@ exports.Router = Router;
75 */
76
77 exports.json = bodyParser.json
79−exports.query = require('./middleware/query');
78 exports.raw = bodyParser.raw
79 exports.static = require('serve-static');
80 exports.text = bodyParser.text
81 exports.urlencoded = bodyParser.urlencoded
84
85−/**
86− * Replace removed middleware with an appropriate error message.
87− */
88
89−var removedMiddlewares = [
90− 'bodyParser',
91− 'compress',
92− 'cookieSession',
93− 'session',
94− 'logger',
95− 'cookieParser',
96− 'favicon',
97− 'responseTime',
98− 'errorHandler',
99− 'timeout',
100− 'methodOverride',
101− 'vhost',
102− 'csrf',
103− 'directory',
104− 'limit',
105− 'multipart',
106− 'staticCache'
107−]
108
109−removedMiddlewares.forEach(function (name) {
110− Object.defineProperty(exports, name, {
111− get: function () {
112− 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.');
113− },
114− configurable: true
115− });
116−});

lib/middleware/init.js

deleted · Implementation · +0 −43 · calm 0
@@ -1,43 +0,0 @@
1−/*!
2− * express
3− * Copyright(c) 2009-2013 TJ Holowaychuk
4− * Copyright(c) 2013 Roman Shtylman
5− * Copyright(c) 2014-2015 Douglas Christopher Wilson
6− * MIT Licensed
7− */
8
9−'use strict';
10
11−/**
12− * Module dependencies.
13− * @private
14− */
15
16−var setPrototypeOf = require('setprototypeof')
17
18−/**
19− * Initialization middleware, exposing the
20− * request and response to each other, as well
21− * as defaulting the X-Powered-By header field.
22− *
23− * @param {Function} app
24− * @return {Function}
25− * @api private
26− */
27
28−exports.init = function(app){
29− return function expressInit(req, res, next){
30− if (app.enabled('x-powered-by')) res.setHeader('X-Powered-By', 'Express');
31− req.res = res;
32− res.req = req;
33− req.next = next;
34
35− setPrototypeOf(req, app.request)
36− setPrototypeOf(res, app.response)
37
38− res.locals = res.locals || Object.create(null);
39
40− next();
41− };
42−};
43

lib/middleware/query.js

deleted · Implementation · +0 −47 · calm 0
@@ -1,47 +0,0 @@
1−/*!
2− * express
3− * Copyright(c) 2009-2013 TJ Holowaychuk
4− * Copyright(c) 2013 Roman Shtylman
5− * Copyright(c) 2014-2015 Douglas Christopher Wilson
6− * MIT Licensed
7− */
8
9−'use strict';
10
11−/**
12− * Module dependencies.
13− */
14
15−var merge = require('utils-merge')
16−var parseUrl = require('parseurl');
17−var qs = require('qs');
18
19−/**
20− * @param {Object} options
21− * @return {Function}
22− * @api public
23− */
24
25−module.exports = function query(options) {
26− var opts = merge({}, options)
27− var queryparse = qs.parse;
28
29− if (typeof options === 'function') {
30− queryparse = options;
31− opts = undefined;
32− }
33
34− if (opts !== undefined && opts.allowPrototypes === undefined) {
35− // back-compat for qs module
36− opts.allowPrototypes = true;
37− }
38
39− return function query(req, res, next){
40− if (!req.query) {
41− var val = parseUrl(req).query;
42− req.query = queryparse(val, opts);
43− }
44
45− next();
46− };
47−};

lib/request.js

modified · Implementation · +38 −48 · calm 0
@@ -14,7 +14,6 @@
14 */
15
16 var accepts = require('accepts');
17−var deprecate = require('depd')('express');
17 var isIP = require('net').isIP;
18 var typeis = require('type-is');
19 var http = require('http');
@@ -147,9 +146,6 @@ req.acceptsEncodings = function(){
146 return accept.encodings.apply(accept, arguments);
147 };
148
150−req.acceptsEncoding = deprecate.function(req.acceptsEncodings,
151− 'req.acceptsEncoding: Use acceptsEncodings instead');
152
149 /**
150 * Check if the given `charset`s are acceptable,
151 * otherwise you should respond with 406 "Not Acceptable".
@@ -164,9 +160,6 @@ req.acceptsCharsets = function(){
160 return accept.charsets.apply(accept, arguments);
161 };
162
167−req.acceptsCharset = deprecate.function(req.acceptsCharsets,
168− 'req.acceptsCharset: Use acceptsCharsets instead');
169
163 /**
164 * Check if the given `lang`s are acceptable,
165 * otherwise you should respond with 406 "Not Acceptable".
@@ -181,9 +174,6 @@ req.acceptsLanguages = function(){
174 return accept.languages.apply(accept, arguments);
175 };
176
184−req.acceptsLanguage = deprecate.function(req.acceptsLanguages,
185− 'req.acceptsLanguage: Use acceptsLanguages instead');
186
177 /**
178 * Parse Range header field, capping to the given `size`.
179 *
@@ -216,38 +206,27 @@ req.range = function range(size, options) {
206 };
207
208 /**
219− * Return the value of param `name` when present or `defaultValue`.
220− *
221− * - Checks route placeholders, ex: _/user/:id_
222− * - Checks body params, ex: id=12, {"id":12}
223− * - Checks query string params, ex: ?id=12
209+ * Parse the query string of `req.url`.
210 *
225− * To utilize request bodies, `req.body`
226− * should be an object. This can be done by using
227− * the `bodyParser()` middleware.
211+ * This uses the "query parser" setting to parse the raw
212+ * string into an object.
213 *
229− * @param {String} name
230− * @param {Mixed} [defaultValue]
214 * @return {String}
232− * @public
215+ * @api public
216 */
217
235−req.param = function param(name, defaultValue) {
236− var params = this.params || {};
237− var body = this.body || {};
238− var query = this.query || {};
218+defineGetter(req, 'query', function query(){
219+ var queryparse = this.app.get('query parser fn');
220
240− var args = arguments.length === 1
241− ? 'name'
242− : 'name, default';
243− deprecate('req.param(' + args + '): Use req.params, req.body, or req.query instead');
221+ if (!queryparse) {
222+ // parsing is disabled
223+ return Object.create(null);
224+ }
225
245− if (null != params[name] && params.hasOwnProperty(name)) return params[name];
246− if (null != body[name]) return body[name];
247− if (null != query[name]) return query[name];
226+ var querystring = parse(this).query;
227
249− return defaultValue;
250−};
First 80 lines.

lib/response.js

modified · Implementation · +39 −191 · calm 0
@@ -15,13 +15,13 @@
15 var Buffer = require('safe-buffer').Buffer
16 var contentDisposition = require('content-disposition');
17 var createError = require('http-errors')
18−var deprecate = require('depd')('express');
18 var encodeUrl = require('encodeurl');
19 var escapeHtml = require('escape-html');
20 var http = require('http');
22−var isAbsolute = require('./utils').isAbsolute;
21 var onFinished = require('on-finished');
22+var mime = require('mime-types')
23 var path = require('path');
24+var pathIsAbsolute = require('path').isAbsolute;
25 var statuses = require('statuses')
26 var merge = require('utils-merge');
27 var sign = require('cookie-signature').sign;
@@ -31,7 +31,6 @@ var setCharset = require('./utils').setCharset;
31 var cookie = require('cookie');
32 var send = require('send');
33 var extname = path.extname;
34−var mime = send.mime;
34 var resolve = path.resolve;
35 var vary = require('vary');
36
@@ -50,24 +49,28 @@ var res = Object.create(http.ServerResponse.prototype)
49 module.exports = res
50
51 /**
53− * Module variables.
54− * @private
55− */
56
57−var charsetRegExp = /;\s*charset\s*=/;
58
59−/**
60− * Set status `code`.
52+ * Set the HTTP status code for the response.
53 *
62− * @param {Number} code
63− * @return {ServerResponse}
54+ * Expects an integer value between 100 and 999 inclusive.
55+ * Throws an error if the provided status code is not an integer or if it's outside the allowable range.
56+ *
57+ * @param {number} code - The HTTP status code to set.
58+ * @return {ServerResponse} - Returns itself for chaining methods.
59+ * @throws {TypeError} If `code` is not an integer.
60+ * @throws {RangeError} If `code` is outside the range 100 to 999.
61 * @public
62 */
63
64 res.status = function status(code) {
68− if ((typeof code === 'string' || Math.floor(code) !== code) && code > 99 && code < 1000) {
69− deprecate('res.status(' + JSON.stringify(code) + '): use res.status(' + Math.floor(code) + ') instead')
65+ // Check if the status code is not an integer
66+ if (!Number.isInteger(code)) {
67+ throw new TypeError(`Invalid status code: ${JSON.stringify(code)}. Status code must be an integer.`);
68 }
69+ // Check if the status code is outside of Node's valid range
70+ if (code < 100 || code > 999) {
71+ throw new RangeError(`Invalid status code: ${JSON.stringify(code)}. Status code must be greater than 99 and less than 1000.`);
72+ }
73+
74 this.statusCode = code;
75 return this;
76 };
@@ -117,31 +120,6 @@ res.send = function send(body) {
120 // settings
121 var app = this.app;
122
120− // allow status / body
121− if (arguments.length === 2) {
122− // res.send(body, status) backwards compat
123− if (typeof arguments[0] !== 'number' && typeof arguments[1] === 'number') {
124− deprecate('res.send(body, status): Use res.status(status).send(body) instead');
125− this.statusCode = arguments[1];
126− } else {
127− deprecate('res.send(status, body): Use res.status(status).send(body) instead');
128− this.statusCode = arguments[0];
129− chunk = arguments[1];
130− }
131− }
132
133− // disambiguate res.send(status) and res.send(status, num)
134− if (typeof chunk === 'number' && arguments.length === 1) {
First 80 lines.

lib/router/layer.js

deleted · Implementation · +0 −181 · calm 0
@@ -1,181 +0,0 @@
1−/*!
2− * express
3− * Copyright(c) 2009-2013 TJ Holowaychuk
4− * Copyright(c) 2013 Roman Shtylman
5− * Copyright(c) 2014-2015 Douglas Christopher Wilson
6− * MIT Licensed
7− */
8
9−'use strict';
10
11−/**
12− * Module dependencies.
13− * @private
14− */
15
16−var pathRegexp = require('path-to-regexp');
17−var debug = require('debug')('express:router:layer');
18
19−/**
20− * Module variables.
21− * @private
22− */
23
24−var hasOwnProperty = Object.prototype.hasOwnProperty;
25
26−/**
27− * Module exports.
28− * @public
29− */
30
31−module.exports = Layer;
32
33−function Layer(path, options, fn) {
34− if (!(this instanceof Layer)) {
35− return new Layer(path, options, fn);
36− }
37
38− debug('new %o', path)
39− var opts = options || {};
40
41− this.handle = fn;
42− this.name = fn.name || '<anonymous>';
43− this.params = undefined;
44− this.path = undefined;
45− this.regexp = pathRegexp(path, this.keys = [], opts);
46
47− // set fast path flags
48− this.regexp.fast_star = path === '*'
49− this.regexp.fast_slash = path === '/' && opts.end === false
50−}
51
52−/**
53− * Handle the error for the layer.
54− *
55− * @param {Error} error
56− * @param {Request} req
57− * @param {Response} res
58− * @param {function} next
59− * @api private
60− */
61
62−Layer.prototype.handle_error = function handle_error(error, req, res, next) {
63− var fn = this.handle;
64
65− if (fn.length !== 4) {
66− // not a standard error handler
67− return next(error);
68− }
69
70− try {
71− fn(error, req, res, next);
72− } catch (err) {
73− next(err);
74− }
75−};
76
77−/**
78− * Handle the request for the layer.
79− *
80− * @param {Request} req
First 80 lines.

lib/router/route.js

deleted · Implementation · +0 −230 · calm 0
@@ -1,230 +0,0 @@
1−/*!
2− * express
3− * Copyright(c) 2009-2013 TJ Holowaychuk
4− * Copyright(c) 2013 Roman Shtylman
5− * Copyright(c) 2014-2015 Douglas Christopher Wilson
6− * MIT Licensed
7− */
8
9−'use strict';
10
11−/**
12− * Module dependencies.
13− * @private
14− */
15
16−var debug = require('debug')('express:router:route');
17−var flatten = require('array-flatten');
18−var Layer = require('./layer');
19−var methods = require('methods');
20
21−/**
22− * Module variables.
23− * @private
24− */
25
26−var slice = Array.prototype.slice;
27−var toString = Object.prototype.toString;
28
29−/**
30− * Module exports.
31− * @public
32− */
33
34−module.exports = Route;
35
36−/**
37− * Initialize `Route` with the given `path`,
38− *
39− * @param {String} path
40− * @public
41− */
42
43−function Route(path) {
44− this.path = path;
45− this.stack = [];
46
47− debug('new %o', path)
48
49− // route handlers for various http methods
50− this.methods = {};
51−}
52
53−/**
54− * Determine if the route handles a given method.
55− * @private
56− */
57
58−Route.prototype._handles_method = function _handles_method(method) {
59− if (this.methods._all) {
60− return true;
61− }
62
63− // normalize name
64− var name = typeof method === 'string'
65− ? method.toLowerCase()
66− : method
67
68− if (name === 'head' && !this.methods['head']) {
69− name = 'get';
70− }
71
72− return Boolean(this.methods[name]);
73−};
74
75−/**
76− * @return {Array} supported HTTP methods
77− * @private
78− */
79
80−Route.prototype._options = function _options() {
First 80 lines.

lib/utils.js

modified · Implementation · +2 −54 · calm 0
@@ -13,12 +13,9 @@
13 */
14
15 var Buffer = require('safe-buffer').Buffer
16−var contentDisposition = require('content-disposition');
16 var contentType = require('content-type');
18−var deprecate = require('depd')('express');
19−var flatten = require('array-flatten');
20−var mime = require('send').mime;
17 var etag = require('etag');
18+var mime = require('mime-types')
19 var proxyaddr = require('proxy-addr');
20 var qs = require('qs');
21 var querystring = require('querystring');
@@ -45,31 +42,6 @@ exports.etag = createETagGenerator({ weak: false })
42
43 exports.wetag = createETagGenerator({ weak: true })
44
48−/**
49− * Check if `path` looks absolute.
50− *
51− * @param {String} path
52− * @return {Boolean}
53− * @api private
54− */
55
56−exports.isAbsolute = function(path){
57− if ('/' === path[0]) return true;
58− if (':' === path[1] && ('\\' === path[2] || '/' === path[2])) return true; // Windows device path
59− if ('\\\\' === path.substring(0, 2)) return true; // Microsoft Azure absolute path
60−};
61
62−/**
63− * Flatten the given `arr`.
64− *
65− * @param {Array} arr
66− * @return {Array}
67− * @api private
68− */
69
70−exports.flatten = deprecate.function(flatten,
71− 'utils.flatten: use array-flatten npm module instead');
72
45 /**
46 * Normalize the given `type`, for example "html" becomes "text/html".
47 *
@@ -81,7 +53,7 @@ exports.flatten = deprecate.function(flatten,
53 exports.normalizeType = function(type){
54 return ~type.indexOf('/')
55 ? acceptParams(type)
84− : { value: mime.lookup(type), params: {} };
56+ : { value: (mime.lookup(type) || 'application/octet-stream'), params: {} }
57 };
58
59 /**
@@ -102,18 +74,6 @@ exports.normalizeTypes = function(types){
74 return ret;
75 };
76
105−/**
106− * Generate Content-Disposition header appropriate for the filename.
107− * non-ascii filenames are urlencoded and a filename* parameter is added
108− *
109− * @param {String} filename
110− * @return {String}
111− * @api private
112− */
113
114−exports.contentDisposition = deprecate.function(contentDisposition,
115− 'utils.contentDisposition: use content-disposition npm module instead');
116
77 /**
78 * Parse accept params `str` returning an
79 * object with `.value`, `.quality` and `.params`.
@@ -192,7 +152,6 @@ exports.compileQueryParser = function compileQueryParser(val) {
152 fn = querystring.parse;
153 break;
154 case false:
195− fn = newObject;
155 break;
156 case 'extended':
157 fn = parseExtendedQueryString;
@@ -290,14 +249,3 @@ function parseExtendedQueryString(str) {
249 allowPrototypes: true
250 });
251 }
First 80 lines.

test/app.router.js

modified · Tests · +228 −202 · medium 8

medium Large file in the diff. 430 changed lines. If it mixes two concerns, ask for a split.

@@ -6,6 +6,7 @@ var express = require('../')
6 , assert = require('assert')
7 , methods = require('methods');
8
9+var describePromises = global.Promise ? describe : describe.skip
10 var shouldSkipQuery = require('./support/utils').shouldSkipQuery
11
12 describe('app.router', function(){
@@ -37,7 +38,7 @@ describe('app.router', function(){
38 })
39
40 describe('methods', function(){
40− methods.concat('del').forEach(function(method){
41+ methods.forEach(function(method){
42 if (method === 'connect') return;
43
44 it('should include ' + method.toUpperCase(), function(done){
@@ -57,7 +58,7 @@ describe('app.router', function(){
58
59 it('should reject numbers for app.' + method, function(){
60 var app = express();
60− assert.throws(app[method].bind(app, '/', 3), /Number/)
61+ assert.throws(app[method].bind(app, '/', 3), /argument handler must be a function/);
62 })
63 });
64
@@ -336,12 +337,12 @@ describe('app.router', function(){
337 var app = express();
338 var router = new express.Router({ mergeParams: true });
339
339− router.get('/*.*', function(req, res){
340+ router.get(/^\/(.*)\.(.*)/, function (req, res) {
341 var keys = Object.keys(req.params).sort();
342 res.send(keys.map(function(k){ return [k, req.params[k]] }));
343 });
344
344− app.use('/user/id:(\\d+)', router);
345+ app.use(/^\/user\/id:(\d+)/, router);
346
347 request(app)
348 .get('/user/id:10/profile.json')
@@ -352,12 +353,12 @@ describe('app.router', function(){
353 var app = express();
354 var router = new express.Router({ mergeParams: true });
355
355− router.get('/*', function(req, res){
356+ router.get(/\/(.*)/, function (req, res) {
357 var keys = Object.keys(req.params).sort();
358 res.send(keys.map(function(k){ return [k, req.params[k]] }));
359 });
360
360− app.use('/user/id:(\\d+)/name:(\\w+)', router);
361+ app.use(/^\/user\/id:(\d+)\/name:(\w+)/, router);
362
363 request(app)
364 .get('/user/id:10/name:tj/profile')
@@ -368,12 +369,12 @@ describe('app.router', function(){
369 var app = express();
370 var router = new express.Router({ mergeParams: true });
371
371− router.get('/name:(\\w+)', function(req, res){
372+ router.get(/\/name:(\w+)/, function(req, res){
373 var keys = Object.keys(req.params).sort();
374 res.send(keys.map(function(k){ return [k, req.params[k]] }));
375 });
376
376− app.use('/user/id:(\\d+)', router);
377+ app.use(/\/user\/id:(\d+)/, router);
378
379 request(app)
380 .get('/user/id:10/name:tj')
@@ -403,11 +404,11 @@ describe('app.router', function(){
404 var app = express();
405 var router = new express.Router({ mergeParams: true });
406
406− router.get('/user:(\\w+)/*', function (req, res, next) {
407+ router.get(/\/user:(\w+)\//, function (req, res, next) {
408 next();
409 });
410
410− app.use('/user/id:(\\d+)', function (req, res, next) {
411+ app.use(/\/user\/id:(\d+)/, function (req, res, next) {
412 router(req, res, function (err) {
413 var keys = Object.keys(req.params).sort();
414 res.send(keys.map(function(k){ return [k, req.params[k]] }));
@@ -574,23 +575,6 @@ describe('app.router', function(){
575 })
576 })
First 80 lines.

test/res.sendFile.js

modified · Tests · +2 −503 · medium 8

medium Large file in the diff. 505 changed lines. If it mixes two concerns, ask for a split.

@@ -1,11 +1,11 @@
1 'use strict'
2
3 var after = require('after');
4+var assert = require('assert')
5 var asyncHooks = tryRequire('async_hooks')
6 var Buffer = require('safe-buffer').Buffer
7 var express = require('../')
8 , request = require('supertest')
8− , assert = require('assert');
9 var onFinished = require('on-finished');
10 var path = require('path');
11 var fixtures = path.join(__dirname, 'fixtures');
@@ -291,7 +291,7 @@ describe('res', function(){
291
292 request(app)
293 .get('/')
294− .expect('Content-Type', 'text/plain; charset=UTF-8')
294+ .expect('Content-Type', 'text/plain; charset=utf-8')
295 .expect(200, 'tobi', cb)
296 })
297
@@ -890,507 +890,6 @@ describe('res', function(){
890 })
891 })
892 })
893
894− describe('.sendfile(path, fn)', function(){
895− it('should invoke the callback when complete', function(done){
896− var app = express();
897− var cb = after(2, done);
898
899− app.use(function(req, res){
900− res.sendfile('test/fixtures/user.html', cb)
901− });
902
903− request(app)
904− .get('/')
905− .expect(200, cb);
906− })
907
908− it('should utilize the same options as express.static()', function(done){
909− var app = express();
910
911− app.use(function(req, res){
912− res.sendfile('test/fixtures/user.html', { maxAge: 60000 });
913− });
914
915− request(app)
916− .get('/')
917− .expect('Cache-Control', 'public, max-age=60')
918− .end(done);
919− })
920
921− it('should invoke the callback when client aborts', function (done) {
922− var cb = after(2, done)
923− var app = express();
924
925− app.use(function (req, res) {
926− setImmediate(function () {
927− res.sendfile('test/fixtures/name.txt', function (err) {
928− assert.ok(err)
929− assert.strictEqual(err.code, 'ECONNABORTED')
930− cb()
931− });
932− });
933− test.req.abort()
934− });
935
936− var server = app.listen()
937− var test = request(server).get('/')
938− test.end(function (err) {
939− assert.ok(err)
940− server.close(cb)
941− })
942− })
943
944− it('should invoke the callback when client already aborted', function (done) {
945− var cb = after(2, done)
946− var app = express();
947
948− app.use(function (req, res) {
949− onFinished(res, function () {
First 80 lines.

test/app.all.js

modified · Tests · +1 −1 · calm 0
@@ -26,7 +26,7 @@ describe('app.all()', function(){
26 var app = express()
27 , n = 0;
28
29− app.all('/*', function(req, res, next){
29+ app.all('/*splat', function(req, res, next){
30 if (n++) return done(new Error('DELETE called several times'));
31 next();
32 });

test/app.js

modified · Tests · +0 −12 · calm 0
@@ -56,18 +56,6 @@ describe('app.mountpath', function(){
56 })
57 })
58
59−describe('app.router', function(){
60− it('should throw with notice', function(done){
61− var app = express()
62
63− try {
64− app.router;
65− } catch(err) {
66− done();
67− }
68− })
69−})
70
59 describe('app.path()', function(){
60 it('should return the canonical', function(){
61 var app = express()

test/app.listen.js

modified · Tests · +14 −0 · calm 0
@@ -1,6 +1,7 @@
1 'use strict'
2
3 var express = require('../')
4+var assert = require('assert')
5
6 describe('app.listen()', function(){
7 it('should wrap with an HTTP server', function(done){
@@ -10,4 +11,17 @@ describe('app.listen()', function(){
11 server.close(done)
12 });
13 })
14+ it('should callback on HTTP server errors', function (done) {
15+ var app1 = express()
16+ var app2 = express()
17+
18+ var server1 = app1.listen(0, function (err) {
19+ assert(!err)
20+ app2.listen(server1.address().port, function (err) {
21+ assert(err.code === 'EADDRINUSE')
22+ server1.close()
23+ done()
24+ })
25+ })
26+ })
27 })

test/app.locals.js

modified · Tests · +2 −1 · calm 0
@@ -5,10 +5,11 @@ var express = require('../')
5
6 describe('app', function(){
7 describe('.locals', function () {
8− it('should default object', function () {
8+ it('should default object with null prototype', function () {
9 var app = express()
10 assert.ok(app.locals)
11 assert.strictEqual(typeof app.locals, 'object')
12+ assert.strictEqual(Object.getPrototypeOf(app.locals), null)
13 })
14
15 describe('.settings', function () {

test/app.options.js

modified · Tests · +10 −10 · calm 0
@@ -7,28 +7,28 @@ describe('OPTIONS', function(){
7 it('should default to the routes defined', function(done){
8 var app = express();
9
10− app.del('/', function(){});
10+ app.post('/', function(){});
11 app.get('/users', function(req, res){});
12 app.put('/users', function(req, res){});
13
14 request(app)
15 .options('/users')
16− .expect('Allow', 'GET,HEAD,PUT')
17− .expect(200, 'GET,HEAD,PUT', done);
16+ .expect('Allow', 'GET, HEAD, PUT')
17+ .expect(200, 'GET, HEAD, PUT', done);
18 })
19
20 it('should only include each method once', function(done){
21 var app = express();
22
23− app.del('/', function(){});
23+ app.delete('/', function(){});
24 app.get('/users', function(req, res){});
25 app.put('/users', function(req, res){});
26 app.get('/users', function(req, res){});
27
28 request(app)
29 .options('/users')
30− .expect('Allow', 'GET,HEAD,PUT')
31− .expect(200, 'GET,HEAD,PUT', done);
30+ .expect('Allow', 'GET, HEAD, PUT')
31+ .expect(200, 'GET, HEAD, PUT', done);
32 })
33
34 it('should not be affected by app.all', function(done){
@@ -45,8 +45,8 @@ describe('OPTIONS', function(){
45 request(app)
46 .options('/users')
47 .expect('x-hit', '1')
48− .expect('Allow', 'GET,HEAD,PUT')
49− .expect(200, 'GET,HEAD,PUT', done);
48+ .expect('Allow', 'GET, HEAD, PUT')
49+ .expect(200, 'GET, HEAD, PUT', done);
50 })
51
52 it('should not respond if the path is not defined', function(done){
@@ -69,8 +69,8 @@ describe('OPTIONS', function(){
69
70 request(app)
71 .options('/other')
72− .expect('Allow', 'GET,HEAD')
73− .expect(200, 'GET,HEAD', done);
72+ .expect('Allow', 'GET, HEAD')
73+ .expect(200, 'GET, HEAD', done);
74 })
75
76 describe('when error occurs in response handler', function () {

test/app.param.js

modified · Tests · +0 −42 · calm 0
@@ -1,51 +1,9 @@
1 'use strict'
2
3−var assert = require('assert')
3 var express = require('../')
4 , request = require('supertest');
5
6 describe('app', function(){
8− describe('.param(fn)', function(){
9− it('should map app.param(name, ...) logic', function(done){
10− var app = express();
11
12− app.param(function(name, regexp){
13− if (Object.prototype.toString.call(regexp) === '[object RegExp]') { // See #1557
14− return function(req, res, next, val){
15− var captures;
16− if (captures = regexp.exec(String(val))) {
17− req.params[name] = captures[1];
18− next();
19− } else {
20− next('route');
21− }
22− }
23− }
24− })
25
26− app.param(':name', /^([a-zA-Z]+)$/);
27
28− app.get('/user/:name', function(req, res){
29− res.send(req.params.name);
30− });
31
32− request(app)
33− .get('/user/tj')
34− .expect(200, 'tj', function (err) {
35− if (err) return done(err)
36− request(app)
37− .get('/user/123')
38− .expect(404, done);
39− });
40
41− })
42
43− it('should fail if not given fn', function(){
44− var app = express();
45− assert.throws(app.param.bind(app, ':name', 'bob'))
46− })
47− })
48
7 describe('.param(names, fn)', function(){
8 it('should map the array', function(done){
9 var app = express();

test/app.route.js

modified · Tests · +135 −0 · calm 0
@@ -3,6 +3,8 @@
3 var express = require('../');
4 var request = require('supertest');
5
6+var describePromises = global.Promise ? describe : describe.skip
7+
8 describe('app.route', function(){
9 it('should return a new route', function(done){
10 var app = express();
@@ -61,4 +63,137 @@ describe('app.route', function(){
63 .get('/test')
64 .expect(404, done);
65 });
66+
67+ describePromises('promise support', function () {
68+ it('should pass rejected promise value', function (done) {
69+ var app = express()
70+ var route = app.route('/foo')
71+
72+ route.all(function createError (req, res, next) {
73+ return Promise.reject(new Error('boom!'))
74+ })
75+
76+ route.all(function helloWorld (req, res) {
77+ res.send('hello, world!')
78+ })
79+
80+ route.all(function handleError (err, req, res, next) {
81+ res.status(500)
82+ res.send('caught: ' + err.message)
83+ })
84+
85+ request(app)
86+ .get('/foo')
87+ .expect(500, 'caught: boom!', done)
88+ })
89+
90+ it('should pass rejected promise without value', function (done) {
91+ var app = express()
92+ var route = app.route('/foo')
93+
94+ route.all(function createError (req, res, next) {
95+ return Promise.reject()
96+ })
97+
98+ route.all(function helloWorld (req, res) {
99+ res.send('hello, world!')
100+ })
101+
102+ route.all(function handleError (err, req, res, next) {
103+ res.status(500)
104+ res.send('caught: ' + err.message)
105+ })
106+
107+ request(app)
108+ .get('/foo')
109+ .expect(500, 'caught: Rejected promise', done)
110+ })
111+
112+ it('should ignore resolved promise', function (done) {
113+ var app = express()
114+ var route = app.route('/foo')
115+
116+ route.all(function createError (req, res, next) {
117+ res.send('saw GET /foo')
118+ return Promise.resolve('foo')
119+ })
120+
121+ route.all(function () {
122+ done(new Error('Unexpected route invoke'))
123+ })
124+
125+ request(app)
126+ .get('/foo')
127+ .expect(200, 'saw GET /foo', done)
128+ })
129+
130+ describe('error handling', function () {
131+ it('should pass rejected promise value', function (done) {
132+ var app = express()
133+ var route = app.route('/foo')
134+
First 80 lines.

test/app.routes.error.js

modified · Tests · +1 −1 · calm 0
@@ -51,7 +51,7 @@ describe('app', function(){
51 assert.ok(b)
52 assert.ok(c)
53 assert.ok(!d)
54− res.send(204);
54+ res.sendStatus(204);
55 });
56
57 request(app)

test/app.use.js

modified · Tests · +5 −5 · calm 0
@@ -258,27 +258,27 @@ describe('app', function(){
258 describe('.use(path, middleware)', function(){
259 it('should require middleware', function () {
260 var app = express()
261− assert.throws(function () { app.use('/') }, /requires a middleware function/)
261+ assert.throws(function () { app.use('/') }, 'TypeError: app.use() requires a middleware function')
262 })
263
264 it('should reject string as middleware', function () {
265 var app = express()
266− assert.throws(function () { app.use('/', 'foo') }, /requires a middleware function but got a string/)
266+ assert.throws(function () { app.use('/', 'foo') }, /argument handler must be a function/)
267 })
268
269 it('should reject number as middleware', function () {
270 var app = express()
271− assert.throws(function () { app.use('/', 42) }, /requires a middleware function but got a number/)
271+ assert.throws(function () { app.use('/', 42) }, /argument handler must be a function/)
272 })
273
274 it('should reject null as middleware', function () {
275 var app = express()
276− assert.throws(function () { app.use('/', null) }, /requires a middleware function but got a Null/)
276+ assert.throws(function () { app.use('/', null) }, /argument handler must be a function/)
277 })
278
279 it('should reject Date as middleware', function () {
280 var app = express()
281− assert.throws(function () { app.use('/', new Date()) }, /requires a middleware function but got a Date/)
281+ assert.throws(function () { app.use('/', new Date()) }, /argument handler must be a function/)
282 })
283
284 it('should strip path from req.url', function (done) {

test/exports.js

modified · Tests · +0 −5 · calm 0
@@ -79,9 +79,4 @@ describe('exports', function(){
79 .get('/')
80 .expect('bar', done);
81 })
82
83− it('should throw on old middlewares', function(){
84− assert.throws(function () { express.bodyParser() }, /Error:.*middleware.*bodyParser/)
85− assert.throws(function () { express.limit() }, /Error:.*middleware.*limit/)
86− })
82 })

test/express.json.js

modified · Tests · +7 −31 · calm 0
@@ -43,12 +43,13 @@ describe('express.json()', function () {
43 .expect(200, '{}', done)
44 })
45
46+ // The old node error message modification in body parser is catching this
47 it('should 400 when only whitespace', function (done) {
48 request(createApp())
49 .post('/')
50 .set('Content-Type', 'application/json')
51 .send(' \n')
51− .expect(400, '[entity.parse.failed] ' + parseError(' '), done)
52+ .expect(400, '[entity.parse.failed] ' + parseError(' \n'), done)
53 })
54
55 it('should 400 when invalid content-length', function (done) {
@@ -72,32 +73,6 @@ describe('express.json()', function () {
73 .expect(400, /content length/, done)
74 })
75
75− it('should 500 if stream not readable', function (done) {
76− var app = express()
77
78− app.use(function (req, res, next) {
79− req.on('end', next)
80− req.resume()
81− })
82
83− app.use(express.json())
84
85− app.use(function (err, req, res, next) {
86− res.status(err.status || 500)
87− res.send('[' + err.type + '] ' + err.message)
88− })
89
90− app.post('/', function (req, res) {
91− res.json(req.body)
92− })
93
94− request(app)
95− .post('/')
96− .set('Content-Type', 'application/json')
97− .send('{"user":"tobi"}')
98− .expect(500, '[stream.not.readable] stream is not readable', done)
99− })
100
76 it('should handle duplicated middleware', function (done) {
77 var app = express()
78
@@ -341,7 +316,7 @@ describe('express.json()', function () {
316 .post('/')
317 .set('Content-Type', 'application/json')
318 .send('{"user":"tobi"}')
344− .expect(200, '{}', done)
319+ .expect(200, '', done)
320 })
321 })
322
@@ -373,7 +348,7 @@ describe('express.json()', function () {
348 .post('/')
349 .set('Content-Type', 'application/x-json')
350 .send('{"user":"tobi"}')
376− .expect(200, '{}', done)
351+ .expect(200, '', done)
352 })
353 })
354
@@ -579,14 +554,14 @@ describe('express.json()', function () {
554 .end(done)
555 })
556
582− it('should presist store when unmatched content-type', function (done) {
557+ it('should persist store when unmatched content-type', function (done) {
558 request(this.app)
559 .post('/')
560 .set('Content-Type', 'application/fizzbuzz')
561 .send('buzz')
562 .expect(200)
563 .expect('x-store-foo', 'bar')
589− .expect('{}')
564+ .expect('')
565 .end(done)
566 })
567
@@ -753,6 +728,7 @@ function createApp (options) {
728 app.use(express.json(options))
729
First 80 lines.

test/express.raw.js

modified · Tests · +2 −33 · calm 0
@@ -65,36 +65,6 @@ describe('express.raw()', function () {
65 .expect(200, { buf: '' }, done)
66 })
67
68− it('should 500 if stream not readable', function (done) {
69− var app = express()
70
71− app.use(function (req, res, next) {
72− req.on('end', next)
73− req.resume()
74− })
75
76− app.use(express.raw())
77
78− app.use(function (err, req, res, next) {
79− res.status(err.status || 500)
80− res.send('[' + err.type + '] ' + err.message)
81− })
82
83− app.post('/', function (req, res) {
84− if (Buffer.isBuffer(req.body)) {
85− res.json({ buf: req.body.toString('hex') })
86− } else {
87− res.json(req.body)
88− }
89− })
90
91− request(app)
92− .post('/')
93− .set('Content-Type', 'application/octet-stream')
94− .send('the user is tobi')
95− .expect(500, '[stream.not.readable] stream is not readable', done)
96− })
97
68 it('should handle duplicated middleware', function (done) {
69 var app = express()
70
@@ -236,7 +206,7 @@ describe('express.raw()', function () {
206 var test = request(this.app).post('/')
207 test.set('Content-Type', 'application/octet-stream')
208 test.write(Buffer.from('000102', 'hex'))
239− test.expect(200, '{}', done)
209+ test.expect(200, '', done)
210 })
211 })
212
@@ -265,7 +235,7 @@ describe('express.raw()', function () {
235 var test = request(this.app).post('/')
236 test.set('Content-Type', 'application/x-foo')
237 test.write(Buffer.from('000102', 'hex'))
268− test.expect(200, '{}', done)
238+ test.expect(200, '', done)
239 })
240 })
241
@@ -420,7 +390,6 @@ describe('express.raw()', function () {
390 .send('buzz')
391 .expect(200)
392 .expect('x-store-foo', 'bar')
423− .expect('{}')
393 .end(done)
394 })
395

test/express.static.js

modified · Tests · +1 −1 · calm 0
@@ -41,7 +41,7 @@ describe('express.static()', function () {
41 it('should set Content-Type', function (done) {
42 request(this.app)
43 .get('/todo.txt')
44− .expect('Content-Type', 'text/plain; charset=UTF-8')
44+ .expect('Content-Type', 'text/plain; charset=utf-8')
45 .expect(200, done)
46 })
47

test/express.text.js

modified · Tests · +2 −29 · calm 0
@@ -61,32 +61,6 @@ describe('express.text()', function () {
61 .expect(200, '""', done)
62 })
63
64− it('should 500 if stream not readable', function (done) {
65− var app = express()
66
67− app.use(function (req, res, next) {
68− req.on('end', next)
69− req.resume()
70− })
71
72− app.use(express.text())
73
74− app.use(function (err, req, res, next) {
75− res.status(err.status || 500)
76− res.send('[' + err.type + '] ' + err.message)
77− })
78
79− app.post('/', function (req, res) {
80− res.json(req.body)
81− })
82
83− request(app)
84− .post('/')
85− .set('Content-Type', 'text/plain')
86− .send('user is tobi')
87− .expect(500, '[stream.not.readable] stream is not readable', done)
88− })
89
64 it('should handle duplicated middleware', function (done) {
65 var app = express()
66
@@ -247,7 +221,7 @@ describe('express.text()', function () {
221 .post('/')
222 .set('Content-Type', 'text/plain')
223 .send('user is tobi')
250− .expect(200, '{}', done)
224+ .expect(200, '', done)
225 })
226 })
227
@@ -277,7 +251,7 @@ describe('express.text()', function () {
251 .post('/')
252 .set('Content-Type', 'text/xml')
253 .send('<user>tobi</user>')
280− .expect(200, '{}', done)
254+ .expect(200, '', done)
255 })
256 })
257
@@ -445,7 +419,6 @@ describe('express.text()', function () {
419 .send('buzz')
420 .expect(200)
421 .expect('x-store-foo', 'bar')
448− .expect('{}')
422 .end(done)
423 })
424

test/express.urlencoded.js

modified · Tests · +4 −31 · calm 0
@@ -62,32 +62,6 @@ describe('express.urlencoded()', function () {
62 .expect(200, '{}', done)
63 })
64
65− it('should 500 if stream not readable', function (done) {
66− var app = express()
67
68− app.use(function (req, res, next) {
69− req.on('end', next)
70− req.resume()
71− })
72
73− app.use(express.urlencoded())
74
75− app.use(function (err, req, res, next) {
76− res.status(err.status || 500)
77− res.send('[' + err.type + '] ' + err.message)
78− })
79
80− app.post('/', function (req, res) {
81− res.json(req.body)
82− })
83
84− request(app)
85− .post('/')
86− .set('Content-Type', 'application/x-www-form-urlencoded')
87− .send('user=tobi')
88− .expect(500, '[stream.not.readable] stream is not readable', done)
89− })
90
65 it('should handle duplicated middleware', function (done) {
66 var app = express()
67
@@ -105,12 +79,12 @@ describe('express.urlencoded()', function () {
79 .expect(200, '{"user":"tobi"}', done)
80 })
81
108− it('should parse extended syntax', function (done) {
82+ it('should not parse extended syntax', function (done) {
83 request(this.app)
84 .post('/')
85 .set('Content-Type', 'application/x-www-form-urlencoded')
86 .send('user[name][first]=Tobi')
113− .expect(200, '{"user":{"name":{"first":"Tobi"}}}', done)
87+ .expect(200, '{"user[name][first]":"Tobi"}', done)
88 })
89
90 describe('with extended option', function () {
@@ -473,7 +447,7 @@ describe('express.urlencoded()', function () {
447 .post('/')
448 .set('Content-Type', 'application/x-www-form-urlencoded')
449 .send('user=tobi')
476− .expect(200, '{}', done)
450+ .expect(200, '', done)
451 })
452 })
453
@@ -505,7 +479,7 @@ describe('express.urlencoded()', function () {
479 .post('/')
480 .set('Content-Type', 'application/x-foo')
481 .send('user=tobi')
508− .expect(200, '{}', done)
482+ .expect(200, '', done)
483 })
484 })
485
@@ -690,7 +664,6 @@ describe('express.urlencoded()', function () {
664 .send('buzz')
665 .expect(200)
666 .expect('x-store-foo', 'bar')
693− .expect('{}')
667 .end(done)
668 })
669

test/req.fresh.js

modified · Tests · +20 −0 · calm 0
@@ -46,5 +46,25 @@ describe('req', function(){
46 .get('/')
47 .expect(200, 'false', done);
48 })
49+
50+ it('should ignore "If-Modified-Since" when "If-None-Match" is present', function(done) {
51+ var app = express();
52+ const etag = '"FooBar"'
53+ const now = Date.now()
54+
55+ app.disable('x-powered-by')
56+ app.use(function(req, res) {
57+ res.set('Etag', etag)
58+ res.set('Last-Modified', new Date(now).toUTCString())
59+ res.send(req.fresh);
60+ });
61+
62+ request(app)
63+ .get('/')
64+ .set('If-Modified-Since', new Date(now - 1000).toUTCString)
65+ .set('If-None-Match', etag)
66+ .expect(304, done);
67+ })
68+
69 })
70 })

test/req.host.js

modified · Tests · +2 −2 · calm 0
@@ -28,7 +28,7 @@ describe('req', function(){
28 request(app)
29 .post('/')
30 .set('Host', 'example.com:3000')
31− .expect('example.com', done);
31+ .expect(200, 'example.com:3000', done);
32 })
33
34 it('should return undefined otherwise', function(done){
@@ -67,7 +67,7 @@ describe('req', function(){
67 request(app)
68 .post('/')
69 .set('Host', '[::1]:3000')
70− .expect('[::1]', done);
70+ .expect(200, '[::1]:3000', done);
71 })
72
73 describe('when "trust proxy" is enabled', function(){

test/req.query.js

modified · Tests · +2 −19 · calm 0
@@ -14,12 +14,12 @@ describe('req', function(){
14 .expect(200, '{}', done);
15 });
16
17− it('should default to parse complex keys', function (done) {
17+ it('should default to parse simple keys', function (done) {
18 var app = createApp();
19
20 request(app)
21 .get('/?user[name]=tj')
22− .expect(200, '{"user":{"name":"tj"}}', done);
22+ .expect(200, '{"user[name]":"tj"}', done);
23 });
24
25 describe('when "query parser" is extended', function () {
@@ -82,23 +82,6 @@ describe('req', function(){
82 });
83 });
84
85− describe('when "query parser fn" is missing', function () {
86− it('should act like "extended"', function (done) {
87− var app = express();
88
89− delete app.settings['query parser'];
90− delete app.settings['query parser fn'];
91
92− app.use(function (req, res) {
93− res.send(req.query);
94− });
95
96− request(app)
97− .get('/?user[name]=tj&user.name=tj')
98− .expect(200, '{"user":{"name":"tj"},"user.name":"tj"}', done);
99− });
100− });
101
85 describe('when "query parser" an unknown value', function () {
86 it('should throw', function () {
87 assert.throws(createApp.bind(null, 'bogus'),

test/req.route.js

modified · Tests · +2 −2 · calm 0
@@ -8,7 +8,7 @@ describe('req', function(){
8 it('should be the executed Route', function(done){
9 var app = express();
10
11− app.get('/user/:id/:op?', function(req, res, next){
11+ app.get('/user/:id{/:op}', function(req, res, next){
12 res.header('path-1', req.route.path)
13 next();
14 });
@@ -20,7 +20,7 @@ describe('req', function(){
20
21 request(app)
22 .get('/user/12/edit')
23− .expect('path-1', '/user/:id/:op?')
23+ .expect('path-1', '/user/:id{/:op}')
24 .expect('path-2', '/user/:id/edit')
25 .expect(200, done)
26 })

test/res.clearCookie.js

modified · Tests · +6 −12 · calm 0
@@ -33,35 +33,29 @@ describe('res', function(){
33 .expect(200, done)
34 })
35
36− it('should set expires when passed', function(done) {
37− var expiresAt = new Date()
36+ it('should ignore maxAge', function(done){
37 var app = express();
38
39 app.use(function(req, res){
41− res.clearCookie('sid', { expires: expiresAt }).end();
40+ res.clearCookie('sid', { path: '/admin', maxAge: 1000 }).end();
41 });
42
43 request(app)
44 .get('/')
46− .expect('Set-Cookie', 'sid=; Path=/; Expires=' + expiresAt.toUTCString() )
45+ .expect('Set-Cookie', 'sid=; Path=/admin; Expires=Thu, 01 Jan 1970 00:00:00 GMT')
46 .expect(200, done)
47 })
48
50− it('should set both maxAge and expires when passed', function(done) {
51− var maxAgeInMs = 10000
52− var expiresAt = new Date()
53− var expectedExpires = new Date(expiresAt.getTime() + maxAgeInMs)
49+ it('should ignore user supplied expires param', function(done){
50 var app = express();
51
52 app.use(function(req, res){
57− res.clearCookie('sid', { expires: expiresAt, maxAge: maxAgeInMs }).end();
53+ res.clearCookie('sid', { path: '/admin', expires: new Date() }).end();
54 });
55
56 request(app)
57 .get('/')
62− // yes, this is the behavior. When we set a max-age, we also set expires to a date 10 sec ahead of expires
63− // even if we set max-age only, we will also set an expires 10 sec in the future
64− .expect('Set-Cookie', 'sid=; Max-Age=10; Path=/; Expires=' + expectedExpires.toUTCString())
58+ .expect('Set-Cookie', 'sid=; Path=/admin; Expires=Thu, 01 Jan 1970 00:00:00 GMT')
59 .expect(200, done)
60 })
61 })

test/res.download.js

modified · Tests · +6 −6 · calm 0
@@ -26,7 +26,7 @@ describe('res', function(){
26
27 request(app)
28 .get('/')
29− .expect('Content-Type', 'text/html; charset=UTF-8')
29+ .expect('Content-Type', 'text/html; charset=utf-8')
30 .expect('Content-Disposition', 'attachment; filename="user.html"')
31 .expect(200, '<p>{{user.name}}</p>', done)
32 })
@@ -69,7 +69,7 @@ describe('res', function(){
69
70 request(app)
71 .get('/')
72− .expect('Content-Type', 'text/html; charset=UTF-8')
72+ .expect('Content-Type', 'text/html; charset=utf-8')
73 .expect('Content-Disposition', 'attachment; filename="document"')
74 .expect(200, done)
75 })
@@ -86,7 +86,7 @@ describe('res', function(){
86
87 request(app)
88 .get('/')
89− .expect('Content-Type', 'text/html; charset=UTF-8')
89+ .expect('Content-Type', 'text/html; charset=utf-8')
90 .expect('Content-Disposition', 'attachment; filename="user.html"')
91 .expect(200, cb);
92 })
@@ -115,7 +115,7 @@ describe('res', function(){
115
116 request(app)
117 .get('/')
118− .expect('Content-Type', 'text/plain; charset=UTF-8')
118+ .expect('Content-Type', 'text/plain; charset=utf-8')
119 .expect('Content-Disposition', 'attachment; filename="name.txt"')
120 .expect(200, 'tobi', cb)
121 })
@@ -369,7 +369,7 @@ describe('res', function(){
369
370 request(app)
371 .get('/')
372− .expect('Content-Type', 'text/html; charset=UTF-8')
372+ .expect('Content-Type', 'text/html; charset=utf-8')
373 .expect('Content-Disposition', 'attachment; filename="document"')
374 .expect(200, cb);
375 })
@@ -388,7 +388,7 @@ describe('res', function(){
388 request(app)
389 .get('/')
390 .expect(200)
391− .expect('Content-Type', 'text/html; charset=UTF-8')
391+ .expect('Content-Type', 'text/html; charset=utf-8')
392 .expect('Content-Disposition', 'attachment; filename="document"')
393 .end(cb)
394 })

test/res.format.js

modified · Tests · +10 −5 · calm 0
@@ -28,7 +28,8 @@ app1.use(function(req, res, next){
28
29 app1.use(function(err, req, res, next){
30 if (!err.types) throw err;
31− res.send(err.status, 'Supports: ' + err.types.join(', '));
31+ res.status(err.status)
32+ res.send('Supports: ' + err.types.join(', '))
33 })
34
35 var app2 = express();
@@ -42,7 +43,8 @@ app2.use(function(req, res, next){
43 });
44
45 app2.use(function(err, req, res, next){
45− res.send(err.status, 'Supports: ' + err.types.join(', '));
46+ res.status(err.status)
47+ res.send('Supports: ' + err.types.join(', '))
48 })
49
50 var app3 = express();
@@ -70,7 +72,8 @@ app4.get('/', function (req, res) {
72 });
73
74 app4.use(function(err, req, res, next){
73− res.send(err.status, 'Supports: ' + err.types.join(', '));
75+ res.status(err.status)
76+ res.send('Supports: ' + err.types.join(', '))
77 })
78
79 var app5 = express();
@@ -103,7 +106,8 @@ describe('res', function(){
106 });
107
108 app.use(function(err, req, res, next){
106− res.send(err.status, 'Supports: ' + err.types.join(', '));
109+ res.status(err.status)
110+ res.send('Supports: ' + err.types.join(', '))
111 });
112
113 test(app);
@@ -164,7 +168,8 @@ describe('res', function(){
168 });
169
170 router.use(function(err, req, res, next){
167− res.send(err.status, 'Supports: ' + err.types.join(', '));
171+ res.status(err.status)
172+ res.send('Supports: ' + err.types.join(', '))
173 })
174
175 app.use(router)

test/res.json.js

modified · Tests · +0 −43 · calm 0
@@ -183,47 +183,4 @@ describe('res', function(){
183 })
184 })
185 })
186
187− describe('.json(status, object)', function(){
188− it('should respond with json and set the .statusCode', function(done){
189− var app = express();
190
191− app.use(function(req, res){
192− res.json(201, { id: 1 });
193− });
194
195− request(app)
196− .get('/')
197− .expect('Content-Type', 'application/json; charset=utf-8')
198− .expect(201, '{"id":1}', done)
199− })
200− })
201
202− describe('.json(object, status)', function(){
203− it('should respond with json and set the .statusCode for backwards compat', function(done){
204− var app = express();
205
206− app.use(function(req, res){
207− res.json({ id: 1 }, 201);
208− });
209
210− request(app)
211− .get('/')
212− .expect('Content-Type', 'application/json; charset=utf-8')
213− .expect(201, '{"id":1}', done)
214− })
215
216− it('should use status as second number for backwards compat', function(done){
217− var app = express();
218
219− app.use(function(req, res){
220− res.json(200, 201);
221− });
222
223− request(app)
224− .get('/')
225− .expect('Content-Type', 'application/json; charset=utf-8')
226− .expect(201, '200', done)
227− })
228− })
186 })

test/res.jsonp.js

modified · Tests · +0 −43 · calm 0
@@ -328,49 +328,6 @@ describe('res', function(){
328 })
329 })
330
331− describe('.jsonp(status, object)', function(){
332− it('should respond with json and set the .statusCode', function(done){
333− var app = express();
334
335− app.use(function(req, res){
336− res.jsonp(201, { id: 1 });
337− });
338
339− request(app)
340− .get('/')
341− .expect('Content-Type', 'application/json; charset=utf-8')
342− .expect(201, '{"id":1}', done)
343− })
344− })
345
346− describe('.jsonp(object, status)', function(){
347− it('should respond with json and set the .statusCode for backwards compat', function(done){
348− var app = express();
349
350− app.use(function(req, res){
351− res.jsonp({ id: 1 }, 201);
352− });
353
354− request(app)
355− .get('/')
356− .expect('Content-Type', 'application/json; charset=utf-8')
357− .expect(201, '{"id":1}', done)
358− })
359
360− it('should use status as second number for backwards compat', function(done){
361− var app = express();
362
363− app.use(function(req, res){
364− res.jsonp(200, 201);
365− });
366
367− request(app)
368− .get('/')
369− .expect('Content-Type', 'application/json; charset=utf-8')
370− .expect(201, '200', done)
371− })
372− })
373
331 it('should not override previous Content-Types', function(done){
332 var app = express();
333

test/res.location.js

modified · Tests · +8 −54 · calm 0
@@ -46,65 +46,19 @@ describe('res', function(){
46 .expect(200, done)
47 })
48
49− describe('when url is "back"', function () {
50− it('should set location from "Referer" header', function (done) {
51− var app = express()
52
53− app.use(function (req, res) {
54− res.location('back').end()
55− })
56
57− request(app)
58− .get('/')
59− .set('Referer', '/some/page.html')
60− .expect('Location', '/some/page.html')
61− .expect(200, done)
62− })
63
64− it('should set location from "Referrer" header', function (done) {
65− var app = express()
66
67− app.use(function (req, res) {
68− res.location('back').end()
69− })
70
71− request(app)
72− .get('/')
73− .set('Referrer', '/some/page.html')
74− .expect('Location', '/some/page.html')
75− .expect(200, done)
76− })
77
78− it('should prefer "Referrer" header', function (done) {
79− var app = express()
80
81− app.use(function (req, res) {
82− res.location('back').end()
83− })
84
85− request(app)
86− .get('/')
87− .set('Referer', '/some/page1.html')
88− .set('Referrer', '/some/page2.html')
89− .expect('Location', '/some/page2.html')
90− .expect(200, done)
91− })
92
93− it('should set the header to "/" without referrer', function (done) {
94− var app = express()
95
96− app.use(function (req, res) {
97− res.location('back').end()
98− })
49+ it('should encode data uri1', function (done) {
50+ var app = express()
51+ app.use(function (req, res) {
52+ res.location('data:text/javascript,export default () => { }').end();
53+ });
54
100− request(app)
55+ request(app)
56 .get('/')
102− .expect('Location', '/')
57+ .expect('Location', 'data:text/javascript,export%20default%20()%20=%3E%20%7B%20%7D')
58 .expect(200, done)
104− })
59 })
60
107− it('should encode data uri', function (done) {
61+ it('should encode data uri2', function (done) {
62 var app = express()
63 app.use(function (req, res) {
64 res.location('data:text/javascript,export default () => { }').end();

test/res.redirect.js

modified · Tests · +0 −15 · calm 0
@@ -61,21 +61,6 @@ describe('res', function(){
61 })
62 })
63
64− describe('.redirect(url, status)', function(){
65− it('should set the response status', function(done){
66− var app = express();
67
68− app.use(function(req, res){
69− res.redirect('http://google.com', 303);
70− });
71
72− request(app)
73− .get('/')
74− .expect('Location', 'http://google.com')
75− .expect(303, done)
76− })
77− })
78
64 describe('when the request method is HEAD', function(){
65 it('should ignore the body', function(done){
66 var app = express();

test/res.send.js

modified · Tests · +6 −51 · calm 0
@@ -53,63 +53,18 @@ describe('res', function(){
53 })
54 })
55
56− describe('.send(code)', function(){
57− it('should set .statusCode', function(done){
58− var app = express();
59
60− app.use(function(req, res){
61− res.send(201)
62− });
63
64− request(app)
65− .get('/')
66− .expect('Created')
67− .expect(201, done);
68− })
69− })
70
71− describe('.send(code, body)', function(){
72− it('should set .statusCode and body', function(done){
73− var app = express();
74
75− app.use(function(req, res){
76− res.send(201, 'Created :)');
77− });
78
79− request(app)
80− .get('/')
81− .expect('Created :)')
82− .expect(201, done);
83− })
84− })
85
86− describe('.send(body, code)', function(){
87− it('should be supported for backwards compat', function(done){
88− var app = express();
89
90− app.use(function(req, res){
91− res.send('Bad!', 400);
92− });
93
94− request(app)
95− .get('/')
96− .expect('Bad!')
97− .expect(400, done);
98− })
99− })
100
101− describe('.send(code, number)', function(){
102− it('should send number as json', function(done){
56+ describe('.send(Number)', function(){
57+ it('should send as application/json', function(done){
58 var app = express();
59
60 app.use(function(req, res){
106− res.send(200, 0.123);
61+ res.send(1000);
62 });
63
64 request(app)
65 .get('/')
66 .expect('Content-Type', 'application/json; charset=utf-8')
112− .expect(200, '0.123', done);
67+ .expect(200, '1000', done)
68 })
69 })
70
@@ -463,7 +418,7 @@ describe('res', function(){
418
419 app.use(function (req, res) {
420 res.set('etag', '"asdf"');
466− res.send(200);
421+ res.send('hello!');
422 });
423
424 app.enable('etag');
@@ -514,7 +469,7 @@ describe('res', function(){
469
470 app.use(function (req, res) {
471 res.set('etag', '"asdf"');
517− res.send(200);
472+ res.send('hello!');
First 80 lines.

test/res.sendStatus.js

modified · Tests · +12 −0 · calm 0
@@ -28,5 +28,17 @@ describe('res', function () {
28 .get('/')
29 .expect(599, '599', done);
30 })
31+
32+ it('should raise error for invalid status code', function (done) {
33+ var app = express()
34+
35+ app.use(function (req, res) {
36+ res.sendStatus(undefined).end()
37+ })
38+
39+ request(app)
40+ .get('/')
41+ .expect(500, /TypeError: Invalid status code/, done)
42+ })
43 })
44 })

test/res.status.js

modified · Tests · +103 −99 · calm 0
@@ -1,55 +1,36 @@
1 'use strict'
2
3−var express = require('../')
4−var request = require('supertest')
5
6−var isIoJs = process.release
7− ? process.release.name === 'io.js'
8− : ['v1.', 'v2.', 'v3.'].indexOf(process.version.slice(0, 3)) !== -1
2+const express = require('../.');
3+const request = require('supertest');
4
5 describe('res', function () {
6 describe('.status(code)', function () {
12− describe('when "code" is undefined', function () {
13− it('should raise error for invalid status code', function (done) {
14− var app = express()
7
16− app.use(function (req, res) {
17− res.status(undefined).end()
18− })
8+ it('should set the status code when valid', function (done) {
9+ var app = express();
10
20− request(app)
21− .get('/')
22− .expect(500, /Invalid status code/, function (err) {
23− if (isIoJs) {
24− done(err ? null : new Error('expected error'))
25− } else {
26− done(err)
27− }
28− })
29− })
30− })
11+ app.use(function (req, res) {
12+ res.status(200).end();
13+ });
14
32− describe('when "code" is null', function () {
33− it('should raise error for invalid status code', function (done) {
15+ request(app)
16+ .get('/')
17+ .expect(200, done);
18+ });
19+
20+ describe('accept valid ranges', function() {
21+ // not testing w/ 100, because that has specific meaning and behavior in Node as Expect: 100-continue
22+ it('should set the response status code to 101', function (done) {
23 var app = express()
24
25 app.use(function (req, res) {
37− res.status(null).end()
26+ res.status(101).end()
27 })
28
29 request(app)
30 .get('/')
42− .expect(500, /Invalid status code/, function (err) {
43− if (isIoJs) {
44− done(err ? null : new Error('expected error'))
45− } else {
46− done(err)
47− }
48− })
31+ .expect(101, done)
32 })
50− })
33
52− describe('when "code" is 201', function () {
34 it('should set the response status code to 201', function (done) {
35 var app = express()
36
@@ -61,9 +42,7 @@ describe('res', function () {
42 .get('/')
43 .expect(201, done)
44 })
64− })
45
66− describe('when "code" is 302', function () {
46 it('should set the response status code to 302', function (done) {
47 var app = express()
First 80 lines.

test/res.type.js

modified · Tests · +1 −1 · calm 0
@@ -14,7 +14,7 @@ describe('res', function(){
14
15 request(app)
16 .get('/')
17− .expect('Content-Type', 'application/javascript; charset=utf-8')
17+ .expect('Content-Type', 'text/javascript; charset=utf-8')
18 .end(done)
19 })
20

test/res.vary.js

modified · Tests · +2 −3 · calm 0
@@ -6,7 +6,7 @@ var utils = require('./support/utils');
6
7 describe('res.vary()', function(){
8 describe('with no arguments', function(){
9− it('should not set Vary', function (done) {
9+ it('should throw error', function (done) {
10 var app = express();
11
12 app.use(function (req, res) {
@@ -16,8 +16,7 @@ describe('res.vary()', function(){
16
17 request(app)
18 .get('/')
19− .expect(utils.shouldNotHaveHeader('Vary'))
20− .expect(200, done);
19+ .expect(500, /field.*required/, done)
20 })
21 })
22

test/Router.js

modified · Tests · +25 −29 · calm 0
@@ -25,7 +25,7 @@ describe('Router', function(){
25 });
26 router.use('/foo', another);
27
28− router.handle({ url: '/foo/bar', method: 'GET' }, { end: done });
28+ router.handle({ url: '/foo/bar', method: 'GET' }, { end: done }, function(){});
29 });
30
31 it('should support dynamic routes', function(done){
@@ -38,7 +38,7 @@ describe('Router', function(){
38 });
39 router.use('/:foo', another);
40
41− router.handle({ url: '/test/route', method: 'GET' }, { end: done });
41+ router.handle({ url: '/test/route', method: 'GET' }, { end: done }, function(){});
42 });
43
44 it('should handle blank URL', function(done){
@@ -102,7 +102,7 @@ describe('Router', function(){
102 res.end();
103 });
104
105− router.handle({ url: '/', method: 'GET' }, { end: done });
105+ router.handle({ url: '/', method: 'GET' }, { end: done }, function(){});
106 });
107
108 it('should not stack overflow with a large sync route stack', function (done) {
@@ -127,7 +127,9 @@ describe('Router', function(){
127 res.end()
128 })
129
130− router.handle({ url: '/foo', method: 'GET' }, { end: done })
130+ router.handle({ url: '/foo', method: 'GET' }, { end: done }, function (err) {
131+ assert(!err, err);
132+ });
133 })
134
135 it('should not stack overflow with a large sync middleware stack', function (done) {
@@ -152,7 +154,9 @@ describe('Router', function(){
154 res.end()
155 })
156
155− router.handle({ url: '/', method: 'GET' }, { end: done })
157+ router.handle({ url: '/', method: 'GET' }, { end: done }, function (err) {
158+ assert(!err, err);
159+ })
160 })
161
162 describe('.handle', function(){
@@ -169,7 +173,7 @@ describe('Router', function(){
173 done();
174 }
175 }
172− router.handle({ url: '/foo', method: 'GET' }, res);
176+ router.handle({ url: '/foo', method: 'GET' }, res, function(){});
177 })
178 })
179
@@ -424,50 +428,32 @@ describe('Router', function(){
428 assert.equal(count, methods.length);
429 done();
430 })
427
428− it('should be called for any URL when "*"', function (done) {
429− var cb = after(4, done)
430− var router = new Router()
431
432− function no () {
433− throw new Error('should not be called')
434− }
435
436− router.all('*', function (req, res) {
437− res.end()
438− })
439
440− router.handle({ url: '/', method: 'GET' }, { end: cb }, no)
441− router.handle({ url: '/foo', method: 'GET' }, { end: cb }, no)
442− router.handle({ url: 'foo', method: 'GET' }, { end: cb }, no)
443− router.handle({ url: '*', method: 'GET' }, { end: cb }, no)
444− })
431 })
432
433 describe('.use', function() {
434 it('should require middleware', function () {
435 var router = new Router()
450− assert.throws(function () { router.use('/') }, /requires a middleware function/)
436+ assert.throws(function () { router.use('/') }, /argument handler is required/)
First 80 lines.

test/utils.js

modified · Tests · +0 −32 · calm 0
@@ -69,35 +69,3 @@ describe('utils.wetag(body, encoding)', function(){
69 'W/"0-2jmj7l5rSw0yVb/vlWAYkK/YBwk"')
70 })
71 })
72
73−describe('utils.isAbsolute()', function(){
74− it('should support windows', function(){
75− assert(utils.isAbsolute('c:\\'));
76− assert(utils.isAbsolute('c:/'));
77− assert(!utils.isAbsolute(':\\'));
78− })
79
80− it('should support windows unc', function(){
81− assert(utils.isAbsolute('\\\\foo\\bar'))
82− })
83
84− it('should support unices', function(){
85− assert(utils.isAbsolute('/foo/bar'));
86− assert(!utils.isAbsolute('foo/bar'));
87− })
88−})
89
90−describe('utils.flatten(arr)', function(){
91− it('should flatten an array', function(){
92− var arr = ['one', ['two', ['three', 'four'], 'five']];
93− var flat = utils.flatten(arr)
94
95− assert.strictEqual(flat.length, 5)
96− assert.strictEqual(flat[0], 'one')
97− assert.strictEqual(flat[1], 'two')
98− assert.strictEqual(flat[2], 'three')
99− assert.strictEqual(flat[3], 'four')
100− assert.strictEqual(flat[4], 'five')
101− assert.ok(flat.every(function (v) { return typeof v === 'string' }))
102− })
103−})

examples/auth/index.js

modified · Docs · +3 −2 · calm 0
@@ -18,7 +18,7 @@ app.set('views', path.join(__dirname, 'views'));
18
19 // middleware
20
21−app.use(express.urlencoded({ extended: false }))
21+app.use(express.urlencoded())
22 app.use(session({
23 resave: false, // don't save session if unmodified
24 saveUninitialized: false, // don't create session until something stored
@@ -102,6 +102,7 @@ app.get('/login', function(req, res){
102 });
103
104 app.post('/login', function (req, res, next) {
105+ if (!req.body) return res.sendStatus(400)
106 authenticate(req.body.username, req.body.password, function(err, user){
107 if (err) return next(err)
108 if (user) {
@@ -115,7 +116,7 @@ app.post('/login', function (req, res, next) {
116 req.session.success = 'Authenticated as ' + user.name
117 + ' click to <a href="/logout">logout</a>. '
118 + ' You may now access <a href="/restricted">/restricted</a>.';
118− res.redirect('back');
119+ res.redirect(req.get('Referrer') || '/');
120 });
121 } else {
122 req.session.error = 'Authentication failed, please check your '

examples/cookies/index.js

modified · Docs · +8 −4 · calm 0
@@ -19,7 +19,7 @@ if (process.env.NODE_ENV !== 'test') app.use(logger(':method :url'))
19 app.use(cookieParser('my secret here'));
20
21 // parses x-www-form-urlencoded
22−app.use(express.urlencoded({ extended: false }))
22+app.use(express.urlencoded())
23
24 app.get('/', function(req, res){
25 if (req.cookies.remember) {
@@ -33,13 +33,17 @@ app.get('/', function(req, res){
33
34 app.get('/forget', function(req, res){
35 res.clearCookie('remember');
36− res.redirect('back');
36+ res.redirect(req.get('Referrer') || '/');
37 });
38
39 app.post('/', function(req, res){
40 var minute = 60000;
41− if (req.body.remember) res.cookie('remember', 1, { maxAge: minute });
42− res.redirect('back');
41+
42+ if (req.body && req.body.remember) {
43+ res.cookie('remember', 1, { maxAge: minute })
44+ }
45+
46+ res.redirect(req.get('Referrer') || '/');
47 });
48
49 /* istanbul ignore next */

examples/downloads/index.js

modified · Docs · +2 −2 · calm 0
@@ -23,8 +23,8 @@ app.get('/', function(req, res){
23
24 // /files/* is accessed via req.params[0]
25 // but here we name it :file
26−app.get('/files/:file(*)', function(req, res, next){
27− res.download(req.params.file, { root: FILES_DIR }, function (err) {
26+app.get('/files/*file', function (req, res, next) {
27+ res.download(req.params.file.join('/'), { root: FILES_DIR }, function (err) {
28 if (!err) return; // file sent
29 if (err.status !== 404) return next(err); // non-404 error
30 // file for download not found

examples/resource/index.js

modified · Docs · +1 −1 · calm 0
@@ -12,7 +12,7 @@ var app = module.exports = express();
12
13 app.resource = function(path, obj) {
14 this.get(path, obj.index);
15− this.get(path + '/:a..:b.:format?', function(req, res){
15+ this.get(path + '/:a..:b{.:format}', function(req, res){
16 var a = parseInt(req.params.a, 10);
17 var b = parseInt(req.params.b, 10);
18 var format = req.params.format;

examples/route-separation/index.js

modified · Docs · +1 −1 · calm 0
@@ -38,7 +38,7 @@ app.get('/', site.index);
38 // User
39
40 app.get('/users', user.list);
41−app.all('/user/:id/:op?', user.load);
41+app.all('/user/:id{/:op}', user.load);
42 app.get('/user/:id', user.view);
43 app.get('/user/:id/view', user.view);
44 app.get('/user/:id/edit', user.edit);

examples/route-separation/user.js

modified · Docs · +1 −1 · calm 0
@@ -43,5 +43,5 @@ exports.update = function(req, res){
43 var user = req.body.user;
44 req.user.name = user.name;
45 req.user.email = user.email;
46− res.redirect('back');
46+ res.redirect(req.get('Referrer') || '/');
47 };

examples/search/index.js

modified · Docs · +2 −2 · calm 0
@@ -35,10 +35,10 @@ db.sadd('cat', 'luna');
35 * GET search for :query.
36 */
37
38−app.get('/search/:query?', function(req, res){
38+app.get('/search/:query?', function(req, res, next){
39 var query = req.params.query;
40 db.smembers(query, function(err, vals){
41− if (err) return res.send(500);
41+ if (err) return next(err);
42 res.send(vals);
43 });
44 });

History.md

modified · Docs · +189 −16 · calm 0
@@ -1,25 +1,198 @@
1−4.21.2 / 2024-11-06
2−==========
1+5.0.0 / 2024-09-10
2+=========================
3+* remove:
4+ - `path-is-absolute` dependency - use `path.isAbsolute` instead
5+* breaking:
6+ * `res.status()` accepts only integers, and input must be greater than 99 and less than 1000
7+ * will throw a `RangeError: Invalid status code: ${code}. Status code must be greater than 99 and less than 1000.` for inputs outside this range
8+ * will throw a `TypeError: Invalid status code: ${code}. Status code must be an integer.` for non integer inputs
9+ * deps: send@1.0.0
10+ * `res.redirect('back')` and `res.location('back')` is no longer a supported magic string, explicitly use `req.get('Referrer') || '/'`.
11+* change:
12+ - `res.clearCookie` will ignore user provided `maxAge` and `expires` options
13+* deps: cookie-signature@^1.2.1
14+* deps: debug@4.3.6
15+* deps: merge-descriptors@^2.0.0
16+* deps: serve-static@^2.1.0
17+* deps: qs@6.13.0
18+* deps: accepts@^2.0.0
19+* deps: mime-types@^3.0.0
20+ - `application/javascript` => `text/javascript`
21+* deps: type-is@^2.0.0
22+* deps: content-disposition@^1.0.0
23+* deps: finalhandler@^2.0.0
24+* deps: fresh@^2.0.0
25+* deps: body-parser@^2.0.1
26+* deps: send@^1.1.0
27+
28+5.0.0-beta.3 / 2024-03-25
29+=========================
30+
31+This incorporates all changes after 4.19.1 up to 4.19.2.
32+
33+5.0.0-beta.2 / 2024-03-20
34+=========================
35+
36+This incorporates all changes after 4.17.2 up to 4.19.1.
37+
38+5.0.0-beta.1 / 2022-02-14
39+=========================
40+
41+This is the first Express 5.0 beta release, based off 4.17.2 and includes
42+changes from 5.0.0-alpha.8.
43+
44+ * change:
45+ - Default "query parser" setting to `'simple'`
46+ - Requires Node.js 4+
47+ - Use `mime-types` for file to content type mapping
48+ * deps: array-flatten@3.0.0
49+ * deps: body-parser@2.0.0-beta.1
50+ - `req.body` is no longer always initialized to `{}`
51+ - `urlencoded` parser now defaults `extended` to `false`
52+ - Use `on-finished` to determine when body read
53+ * deps: router@2.0.0-beta.1
54+ - Add new `?`, `*`, and `+` parameter modifiers
55+ - Internalize private `router.process_params` method
56+ - Matching group expressions are only RegExp syntax
57+ - Named matching groups no longer available by position in `req.params`
58+ - Regular expressions can only be used in a matching group
59+ - Remove `debug` dependency
60+ - Special `*` path segment behavior removed
61+ - deps: array-flatten@3.0.0
62+ - deps: parseurl@~1.3.3
63+ - deps: path-to-regexp@3.2.0
64+ - deps: setprototypeof@1.2.0
65+ * deps: send@1.0.0-beta.1
66+ - Change `dotfiles` option default to `'ignore'`
67+ - Remove `hidden` option; use `dotfiles` option instead
68+ - Use `mime-types` for file to content type mapping
69+ - deps: debug@3.1.0
70+ * deps: serve-static@2.0.0-beta.1
71+ - Change `dotfiles` option default to `'ignore'`
72+ - Remove `hidden` option; use `dotfiles` option instead
73+ - Use `mime-types` for file to content type mapping
74+ - deps: send@1.0.0-beta.1
75+
76+5.0.0-alpha.8 / 2020-03-25
77+==========================
78+
First 80 lines.