mirror of
https://github.com/zebrajr/express.git
synced 2025-12-06 00:19:48 +01:00
Compare commits
179 Commits
2a980ad160
...
caa4f68ee8
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
caa4f68ee8 | ||
|
|
6ed3439584 | ||
|
|
327af123a1 | ||
|
|
d2de128a32 | ||
|
|
2a53336e5d | ||
|
|
a42413d4e3 | ||
|
|
c2f576cbe9 | ||
|
|
99473c593a | ||
|
|
2d589b644a | ||
|
|
85e48bb8c1 | ||
|
|
55869f49a6 | ||
|
|
af7cd90893 | ||
|
|
ae6a4621bc | ||
|
|
8d39345902 | ||
|
|
a5cb681eb8 | ||
|
|
511d9dfca8 | ||
|
|
7f13d572c1 | ||
|
|
62336717bf | ||
|
|
3bbffdc41c | ||
|
|
ff86319ed5 | ||
|
|
1c5cf0fead | ||
|
|
256a3d1527 | ||
|
|
4f952a953b | ||
|
|
41113599af | ||
|
|
6a40af8293 | ||
|
|
246f6f5aee | ||
|
|
b11122be85 | ||
|
|
43020ff275 | ||
|
|
e4a61bd88e | ||
|
|
39f5d633b5 | ||
|
|
52ed64606f | ||
|
|
4e92ac9031 | ||
|
|
9f8589e31c | ||
|
|
cc751cff8f | ||
|
|
805ef52ae6 | ||
|
|
9e3dbb4374 | ||
|
|
b31910c542 | ||
|
|
c70197ad33 | ||
|
|
8cb53ea5c3 | ||
|
|
e162764f0f | ||
|
|
508c74091f | ||
|
|
b274047a5d | ||
|
|
082d6d1253 | ||
|
|
94546a3cc5 | ||
|
|
ab02240336 | ||
|
|
a46cfdc37f | ||
|
|
d14b2de782 | ||
|
|
2027b87a27 | ||
|
|
2cbf22721d | ||
|
|
3e1a1cedb2 | ||
|
|
6340d1509f | ||
|
|
344b022fc7 | ||
|
|
0c49926a9b | ||
|
|
b3906cbdde | ||
|
|
fed8c2a885 | ||
|
|
bdd81f8670 | ||
|
|
6c98f80b6a | ||
|
|
f9256ef36f | ||
|
|
e5feb9fcc9 | ||
|
|
21df421ebc | ||
|
|
4c9ddc1c47 | ||
|
|
9ebe5d500d | ||
|
|
ec4a01b6b8 | ||
|
|
54271f69b5 | ||
|
|
0264908903 | ||
|
|
4d713d2b76 | ||
|
|
125bb742a3 | ||
|
|
accafc652e | ||
|
|
05f40f4321 | ||
|
|
402e7f653f | ||
|
|
4e61d0100d | ||
|
|
7748475747 | ||
|
|
91a58b5b03 | ||
|
|
13e6894393 | ||
|
|
65b62065d2 | ||
|
|
0b243b1aee | ||
|
|
09831580ec | ||
|
|
41c054cff1 | ||
|
|
ecf762ff38 | ||
|
|
63992bb1d7 | ||
|
|
ea49706052 | ||
|
|
dde1f7d6e8 | ||
|
|
82fc12a40b | ||
|
|
9c756b0105 | ||
|
|
160b91cbf7 | ||
|
|
d106bf5324 | ||
|
|
723b5451bb | ||
|
|
c96c690dc0 | ||
|
|
088856c3f8 | ||
|
|
ee40a881f5 | ||
|
|
26801a0afd | ||
|
|
14439731f9 | ||
|
|
4b3b8cc231 | ||
|
|
e9bcdd399b | ||
|
|
cd7d79f92a | ||
|
|
5e2345e966 | ||
|
|
6415f7035b | ||
|
|
04bc62787b | ||
|
|
da4d763ff6 | ||
|
|
7091ec17f0 | ||
|
|
416ba025a1 | ||
|
|
60fb1d2acd | ||
|
|
e9f9aaeebd | ||
|
|
318fd4b543 | ||
|
|
6faf26d59f | ||
|
|
5213bd9fe7 | ||
|
|
669c805615 | ||
|
|
620df0e35e | ||
|
|
f6db4ee805 | ||
|
|
a0276c6c91 | ||
|
|
3d05e85b0c | ||
|
|
450c468d04 | ||
|
|
af341b0f09 | ||
|
|
1574925cad | ||
|
|
c7d528cdc0 | ||
|
|
8aabecaf1f | ||
|
|
bd04d8a87f | ||
|
|
121fe9982b | ||
|
|
5f0c829d7c | ||
|
|
c82fa19447 | ||
|
|
fa22245cc6 | ||
|
|
302a6152b4 | ||
|
|
659fcc1598 | ||
|
|
a163e2cdf4 | ||
|
|
62e12fe710 | ||
|
|
8fabed82aa | ||
|
|
f4120a6453 | ||
|
|
19c8d64855 | ||
|
|
71395f5933 | ||
|
|
e3bd14dcca | ||
|
|
c319fe260a | ||
|
|
21f725e0ef | ||
|
|
e5dbb0cb4e | ||
|
|
a3a9166c52 | ||
|
|
06f423d4f5 | ||
|
|
501e24e0a9 | ||
|
|
c8d9223e93 | ||
|
|
4b39a01e6a | ||
|
|
ad4d52de29 | ||
|
|
07077c4457 | ||
|
|
bcbb9d56c5 | ||
|
|
ab1c9e924e | ||
|
|
25fdefac45 | ||
|
|
a856456a95 | ||
|
|
1dbfee6623 | ||
|
|
8a387d3ede | ||
|
|
943f28f05f | ||
|
|
7cafdb5824 | ||
|
|
2c668f87c7 | ||
|
|
6343288bef | ||
|
|
694869d2aa | ||
|
|
cec5780db4 | ||
|
|
21d52daafb | ||
|
|
a7d15f382e | ||
|
|
6c751191dd | ||
|
|
1e2951a832 | ||
|
|
3a1f27fcde | ||
|
|
b309b873f1 | ||
|
|
f90e045334 | ||
|
|
f6ec710534 | ||
|
|
a9ef9e13fb | ||
|
|
f56e2a2503 | ||
|
|
8a5ecd3d89 | ||
|
|
4052c15c7f | ||
|
|
97ccc52207 | ||
|
|
0fc4f0735a | ||
|
|
ccdbe4ea37 | ||
|
|
59f2b4048a | ||
|
|
7f2532808a | ||
|
|
be35e4927c | ||
|
|
f31dcff10c | ||
|
|
509ebb1aff | ||
|
|
78e50547f1 | ||
|
|
dcc4eaabe8 | ||
|
|
8c6f9c4253 | ||
|
|
88103063fe | ||
|
|
164638b24f | ||
|
|
e66625be50 | ||
|
|
085a29685a |
|
|
@ -1,4 +1,4 @@
|
|||
# http://editorconfig.org
|
||||
# https://editorconfig.org
|
||||
root = true
|
||||
|
||||
[*]
|
||||
|
|
|
|||
|
|
@ -1,5 +1,7 @@
|
|||
root: true
|
||||
|
||||
env:
|
||||
es2022: true
|
||||
node: true
|
||||
rules:
|
||||
eol-last: error
|
||||
eqeqeq: [error, allow-null]
|
||||
|
|
|
|||
140
.github/workflows/ci.yml
vendored
140
.github/workflows/ci.yml
vendored
|
|
@ -7,12 +7,16 @@ on:
|
|||
- develop
|
||||
- '4.x'
|
||||
- '5.x'
|
||||
- '5.0'
|
||||
paths-ignore:
|
||||
- '*.md'
|
||||
pull_request:
|
||||
paths-ignore:
|
||||
- '*.md'
|
||||
|
||||
permissions:
|
||||
contents: read
|
||||
|
||||
# Cancel in progress workflows
|
||||
# in the scenario where we already had a run going for that PR/branch/tag but then triggered a new run
|
||||
concurrency:
|
||||
|
|
@ -25,90 +29,26 @@ jobs:
|
|||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- name: Setup Node.js {{ matrix.node-version }}
|
||||
- name: Setup Node.js
|
||||
uses: actions/setup-node@v4
|
||||
with:
|
||||
node-version: 'lts/*'
|
||||
persist-credentials: false
|
||||
|
||||
- name: Install dependencies
|
||||
run: npm install --ignore-scripts --only=dev
|
||||
run: npm install --ignore-scripts --include=dev
|
||||
|
||||
- name: Run lint
|
||||
run: npm run lint
|
||||
|
||||
test:
|
||||
name: Run tests
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
os: [ubuntu-latest, windows-latest]
|
||||
node-version:
|
||||
- "0.10"
|
||||
- "0.12"
|
||||
- "4"
|
||||
- "5"
|
||||
- "6"
|
||||
- "7"
|
||||
- "8"
|
||||
- "9"
|
||||
- "10"
|
||||
- "11"
|
||||
- "12"
|
||||
- "13"
|
||||
- "14"
|
||||
- "15"
|
||||
- "16"
|
||||
- "17"
|
||||
- "18"
|
||||
- "19"
|
||||
- "20"
|
||||
- "21"
|
||||
- "22"
|
||||
# Use supported versions of our testing tools under older versions of Node
|
||||
# Install npm in some specific cases where we need to
|
||||
include:
|
||||
- node-version: "0.10"
|
||||
npm-i: "mocha@3.5.3 nyc@10.3.2 supertest@2.0.0"
|
||||
# Npm isn't being installed on windows w/ setup-node for
|
||||
# 0.10 and 0.12, which will end up choking when npm uses es6
|
||||
npm-version: "npm@2.15.1"
|
||||
node-version: [18, 19, 20, 21, 22, 23]
|
||||
# Node.js release schedule: https://nodejs.org/en/about/releases/
|
||||
|
||||
- node-version: "0.12"
|
||||
npm-i: "mocha@3.5.3 nyc@10.3.2 supertest@2.0.0"
|
||||
npm-version: "npm@2.15.11"
|
||||
|
||||
- node-version: "4"
|
||||
npm-i: "mocha@5.2.0 nyc@11.9.0 supertest@3.4.2"
|
||||
|
||||
- node-version: "5"
|
||||
npm-i: "mocha@5.2.0 nyc@11.9.0 supertest@3.4.2"
|
||||
# fixes https://github.com/npm/cli/issues/681
|
||||
npm-version: "npm@3.10.10"
|
||||
|
||||
- node-version: "6"
|
||||
npm-i: "mocha@6.2.2 nyc@14.1.1 supertest@3.4.2"
|
||||
|
||||
- node-version: "7"
|
||||
npm-i: "mocha@6.2.2 nyc@14.1.1 supertest@6.1.6"
|
||||
|
||||
- node-version: "8"
|
||||
npm-i: "mocha@7.2.0 nyc@14.1.1"
|
||||
|
||||
- node-version: "9"
|
||||
npm-i: "mocha@7.2.0 nyc@14.1.1"
|
||||
|
||||
- node-version: "10"
|
||||
npm-i: "mocha@8.4.0"
|
||||
|
||||
- node-version: "11"
|
||||
npm-i: "mocha@8.4.0"
|
||||
|
||||
- node-version: "12"
|
||||
npm-i: "mocha@9.2.2"
|
||||
|
||||
- node-version: "13"
|
||||
npm-i: "mocha@9.2.2"
|
||||
name: Node.js ${{ matrix.node-version }} - ${{matrix.os}}
|
||||
|
||||
runs-on: ${{ matrix.os }}
|
||||
steps:
|
||||
|
|
@ -121,10 +61,6 @@ jobs:
|
|||
with:
|
||||
node-version: ${{ matrix.node-version }}
|
||||
|
||||
- name: Npm version fixes
|
||||
if: ${{matrix.npm-version != ''}}
|
||||
run: npm install -g ${{ matrix.npm-version }}
|
||||
|
||||
- name: Configure npm loglevel
|
||||
run: |
|
||||
npm config set loglevel error
|
||||
|
|
@ -133,13 +69,6 @@ jobs:
|
|||
- name: Install dependencies
|
||||
run: npm install
|
||||
|
||||
- name: Install Node version specific dev deps
|
||||
if: ${{ matrix.npm-i != '' }}
|
||||
run: npm install --save-dev ${{ matrix.npm-i }}
|
||||
|
||||
- name: Remove non-test dependencies
|
||||
run: npm rm --silent --save-dev connect-redis
|
||||
|
||||
- name: Output Node and NPM versions
|
||||
run: |
|
||||
echo "Node.js version: $(node -v)"
|
||||
|
|
@ -147,44 +76,39 @@ jobs:
|
|||
|
||||
- name: Run tests
|
||||
shell: bash
|
||||
run: |
|
||||
npm run test-ci
|
||||
cp coverage/lcov.info "coverage/${{ matrix.node-version }}.lcov"
|
||||
|
||||
- name: Collect code coverage
|
||||
run: |
|
||||
mv ./coverage "./${{ matrix.node-version }}"
|
||||
mkdir ./coverage
|
||||
mv "./${{ matrix.node-version }}" "./coverage/${{ matrix.node-version }}"
|
||||
run: npm run test-ci
|
||||
|
||||
- name: Upload code coverage
|
||||
uses: actions/upload-artifact@v3
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: coverage
|
||||
path: ./coverage
|
||||
name: coverage-node-${{ matrix.node-version }}-${{ matrix.os }}
|
||||
path: ./coverage/lcov.info
|
||||
retention-days: 1
|
||||
|
||||
coverage:
|
||||
needs: test
|
||||
runs-on: ubuntu-latest
|
||||
permissions:
|
||||
contents: read
|
||||
checks: write
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: actions/checkout@v4
|
||||
|
||||
- name: Install lcov
|
||||
shell: bash
|
||||
run: sudo apt-get -y install lcov
|
||||
- name: Install lcov
|
||||
shell: bash
|
||||
run: sudo apt-get -y install lcov
|
||||
|
||||
- name: Collect coverage reports
|
||||
uses: actions/download-artifact@v3
|
||||
with:
|
||||
name: coverage
|
||||
path: ./coverage
|
||||
- name: Collect coverage reports
|
||||
uses: actions/download-artifact@v4
|
||||
with:
|
||||
path: ./coverage
|
||||
pattern: coverage-node-*
|
||||
|
||||
- name: Merge coverage reports
|
||||
shell: bash
|
||||
run: find ./coverage -name lcov.info -exec printf '-a %q\n' {} \; | xargs lcov -o ./coverage/lcov.info
|
||||
- name: Merge coverage reports
|
||||
shell: bash
|
||||
run: find ./coverage -name lcov.info -exec printf '-a %q\n' {} \; | xargs lcov -o ./lcov.info
|
||||
|
||||
- name: Upload coverage report
|
||||
uses: coverallsapp/github-action@master
|
||||
with:
|
||||
github-token: ${{ secrets.GITHUB_TOKEN }}
|
||||
- name: Upload coverage report
|
||||
uses: coverallsapp/github-action@v2
|
||||
with:
|
||||
file: ./lcov.info
|
||||
|
|
|
|||
69
.github/workflows/iojs.yml
vendored
69
.github/workflows/iojs.yml
vendored
|
|
@ -1,69 +0,0 @@
|
|||
name: iojs-ci
|
||||
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- master
|
||||
- '4.x'
|
||||
paths-ignore:
|
||||
- '*.md'
|
||||
pull_request:
|
||||
paths-ignore:
|
||||
- '*.md'
|
||||
|
||||
concurrency:
|
||||
group: "${{ github.workflow }} ✨ ${{ github.event.pull_request.head.label || github.head_ref || github.ref }}"
|
||||
cancel-in-progress: true
|
||||
|
||||
jobs:
|
||||
test:
|
||||
runs-on: ubuntu-latest
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
node-version: ["1.8", "2.5", "3.3"]
|
||||
include:
|
||||
- node-version: "1.8"
|
||||
npm-i: "mocha@3.5.3 nyc@10.3.2 supertest@2.0.0"
|
||||
- node-version: "2.5"
|
||||
npm-i: "mocha@3.5.3 nyc@10.3.2 supertest@2.0.0"
|
||||
- node-version: "3.3"
|
||||
npm-i: "mocha@3.5.3 nyc@10.3.2 supertest@2.0.0"
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
|
||||
- name: Install iojs ${{ matrix.node-version }}
|
||||
shell: bash -eo pipefail -l {0}
|
||||
run: |
|
||||
nvm install --default ${{ matrix.node-version }}
|
||||
dirname "$(nvm which ${{ matrix.node-version }})" >> "$GITHUB_PATH"
|
||||
|
||||
- name: Configure npm
|
||||
run: |
|
||||
npm config set loglevel error
|
||||
npm config set shrinkwrap false
|
||||
|
||||
- name: Install npm module(s) ${{ matrix.npm-i }}
|
||||
run: npm install --save-dev ${{ matrix.npm-i }}
|
||||
if: matrix.npm-i != ''
|
||||
|
||||
- name: Remove non-test dependencies
|
||||
run: npm rm --silent --save-dev connect-redis
|
||||
|
||||
- name: Install Node.js dependencies
|
||||
run: npm install
|
||||
|
||||
- name: List environment
|
||||
id: list_env
|
||||
shell: bash
|
||||
run: |
|
||||
echo "node@$(node -v)"
|
||||
echo "npm@$(npm -v)"
|
||||
npm -s ls ||:
|
||||
(npm -s ls --depth=0 ||:) | awk -F'[ @]' 'NR>1 && $2 { print $2 "=" $3 }' >> "$GITHUB_OUTPUT"
|
||||
|
||||
- name: Run tests
|
||||
shell: bash
|
||||
run: npm run test
|
||||
|
||||
98
.github/workflows/legacy.yml
vendored
Normal file
98
.github/workflows/legacy.yml
vendored
Normal file
|
|
@ -0,0 +1,98 @@
|
|||
name: legacy
|
||||
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- master
|
||||
- develop
|
||||
- '4.x'
|
||||
- '5.x'
|
||||
- '5.0'
|
||||
paths-ignore:
|
||||
- '*.md'
|
||||
pull_request:
|
||||
paths-ignore:
|
||||
- '*.md'
|
||||
|
||||
permissions:
|
||||
contents: read
|
||||
|
||||
# Cancel in progress workflows
|
||||
# in the scenario where we already had a run going for that PR/branch/tag but then triggered a new run
|
||||
concurrency:
|
||||
group: "${{ github.workflow }} ✨ ${{ github.event.pull_request.head.label || github.head_ref || github.ref }}"
|
||||
cancel-in-progress: true
|
||||
|
||||
jobs:
|
||||
test:
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
os: [ubuntu-latest, windows-latest]
|
||||
node-version: [16, 17]
|
||||
# Node.js release schedule: https://nodejs.org/en/about/releases/
|
||||
|
||||
name: Node.js ${{ matrix.node-version }} - ${{matrix.os}}
|
||||
|
||||
runs-on: ${{ matrix.os }}
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
with:
|
||||
persist-credentials: false
|
||||
|
||||
- name: Setup Node.js ${{ matrix.node-version }}
|
||||
uses: actions/setup-node@v4
|
||||
with:
|
||||
node-version: ${{ matrix.node-version }}
|
||||
|
||||
- name: Configure npm loglevel
|
||||
run: |
|
||||
npm config set loglevel error
|
||||
shell: bash
|
||||
|
||||
- name: Install dependencies
|
||||
run: npm install
|
||||
|
||||
- name: Output Node and NPM versions
|
||||
run: |
|
||||
echo "Node.js version: $(node -v)"
|
||||
echo "NPM version: $(npm -v)"
|
||||
|
||||
- name: Run tests
|
||||
shell: bash
|
||||
run: npm run test-ci
|
||||
|
||||
- name: Upload code coverage
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: coverage-node-${{ matrix.node-version }}-${{ matrix.os }}
|
||||
path: ./coverage/lcov.info
|
||||
retention-days: 1
|
||||
|
||||
coverage:
|
||||
needs: test
|
||||
runs-on: ubuntu-latest
|
||||
permissions:
|
||||
contents: read
|
||||
checks: write
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
|
||||
- name: Install lcov
|
||||
shell: bash
|
||||
run: sudo apt-get -y install lcov
|
||||
|
||||
- name: Collect coverage reports
|
||||
uses: actions/download-artifact@v4
|
||||
with:
|
||||
path: ./coverage
|
||||
pattern: coverage-node-*
|
||||
|
||||
- name: Merge coverage reports
|
||||
shell: bash
|
||||
run: find ./coverage -name lcov.info -exec printf '-a %q\n' {} \; | xargs lcov -o ./lcov.info
|
||||
|
||||
- name: Upload coverage report
|
||||
uses: coverallsapp/github-action@v2
|
||||
with:
|
||||
file: ./lcov.info
|
||||
72
.github/workflows/scorecard.yml
vendored
Normal file
72
.github/workflows/scorecard.yml
vendored
Normal file
|
|
@ -0,0 +1,72 @@
|
|||
# This workflow uses actions that are not certified by GitHub. They are provided
|
||||
# by a third-party and are governed by separate terms of service, privacy
|
||||
# policy, and support documentation.
|
||||
|
||||
name: Scorecard supply-chain security
|
||||
on:
|
||||
# For Branch-Protection check. Only the default branch is supported. See
|
||||
# https://github.com/ossf/scorecard/blob/main/docs/checks.md#branch-protection
|
||||
branch_protection_rule:
|
||||
# To guarantee Maintained check is occasionally updated. See
|
||||
# https://github.com/ossf/scorecard/blob/main/docs/checks.md#maintained
|
||||
schedule:
|
||||
- cron: '16 21 * * 1'
|
||||
push:
|
||||
branches: [ "master" ]
|
||||
|
||||
# Declare default permissions as read only.
|
||||
permissions: read-all
|
||||
|
||||
jobs:
|
||||
analysis:
|
||||
name: Scorecard analysis
|
||||
runs-on: ubuntu-latest
|
||||
permissions:
|
||||
# Needed to upload the results to code-scanning dashboard.
|
||||
security-events: write
|
||||
# Needed to publish results and get a badge (see publish_results below).
|
||||
id-token: write
|
||||
# Uncomment the permissions below if installing in a private repository.
|
||||
# contents: read
|
||||
# actions: read
|
||||
|
||||
steps:
|
||||
- name: "Checkout code"
|
||||
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
|
||||
with:
|
||||
persist-credentials: false
|
||||
|
||||
- name: "Run analysis"
|
||||
uses: ossf/scorecard-action@62b2cac7ed8198b15735ed49ab1e5cf35480ba46 # v2.4.0
|
||||
with:
|
||||
results_file: results.sarif
|
||||
results_format: sarif
|
||||
# (Optional) "write" PAT token. Uncomment the `repo_token` line below if:
|
||||
# - you want to enable the Branch-Protection check on a *public* repository, or
|
||||
# - you are installing Scorecard on a *private* repository
|
||||
# To create the PAT, follow the steps in https://github.com/ossf/scorecard-action#authentication-with-pat.
|
||||
# repo_token: ${{ secrets.SCORECARD_TOKEN }}
|
||||
|
||||
# Public repositories:
|
||||
# - Publish results to OpenSSF REST API for easy access by consumers
|
||||
# - Allows the repository to include the Scorecard badge.
|
||||
# - See https://github.com/ossf/scorecard-action#publishing-results.
|
||||
# For private repositories:
|
||||
# - `publish_results` will always be set to `false`, regardless
|
||||
# of the value entered here.
|
||||
publish_results: true
|
||||
|
||||
# Upload the results as artifacts (optional). Commenting out will disable uploads of run results in SARIF
|
||||
# format to the repository Actions tab.
|
||||
- name: "Upload artifact"
|
||||
uses: actions/upload-artifact@65c4c4a1ddee5b72f698fdd19549f0f0fb45cf08 # v4.6.0
|
||||
with:
|
||||
name: SARIF file
|
||||
path: results.sarif
|
||||
retention-days: 5
|
||||
|
||||
# Upload the results to GitHub's code scanning dashboard.
|
||||
- name: "Upload to code-scanning"
|
||||
uses: github/codeql-action/upload-sarif@dd746615b3b9d728a6a37ca2045b68ca76d4841a # v3.28.8
|
||||
with:
|
||||
sarif_file: results.sarif
|
||||
|
|
@ -20,11 +20,11 @@ alike.
|
|||
|
||||
Express is made of many modules spread between three GitHub Orgs:
|
||||
|
||||
- [expressjs](http://github.com/expressjs/): Top level middleware and
|
||||
- [expressjs](https://github.com/expressjs/): Top level middleware and
|
||||
libraries
|
||||
- [pillarjs](http://github.com/pillarjs/): Components which make up
|
||||
- [pillarjs](https://github.com/pillarjs/): Components which make up
|
||||
Express but can also be used for other web frameworks
|
||||
- [jshttp](http://github.com/jshttp/): Low level HTTP libraries
|
||||
- [jshttp](https://github.com/jshttp/): Low level HTTP libraries
|
||||
|
||||
### 1.2: Out-of-Scope
|
||||
|
||||
|
|
|
|||
|
|
@ -7,7 +7,7 @@ Open issues for the expressjs.com website in https://github.com/expressjs/expres
|
|||
## PRs and Code contributions
|
||||
|
||||
* Tests must pass.
|
||||
* Follow the [JavaScript Standard Style](http://standardjs.com/) and `npm run lint`.
|
||||
* Follow the [JavaScript Standard Style](https://standardjs.com/) and `npm run lint`.
|
||||
* If you fix a bug, add a test.
|
||||
|
||||
## Branches
|
||||
|
|
|
|||
171
Contributing.md
171
Contributing.md
|
|
@ -132,78 +132,113 @@ Like TC members, Repo captains are a subset of committers.
|
|||
To become a captain for a project the candidate is expected to participate in that
|
||||
project for at least 6 months as a committer prior to the request. They should have
|
||||
helped with code contributions as well as triaging issues. They are also required to
|
||||
have 2FA enabled on both their GitHub and npm accounts. Any TC member or existing
|
||||
captain on the repo can nominate another committer to the captain role, submit a PR to
|
||||
this doc, under `Current Project Captains` section (maintaining the sort order) with
|
||||
the project, their GitHub handle and npm username (if different). The PR will require
|
||||
at least 2 approvals from TC members and 2 weeks hold time to allow for comment and/or
|
||||
dissent. When the PR is merged, a TC member will add them to the proper GitHub/npm groups.
|
||||
have 2FA enabled on both their GitHub and npm accounts.
|
||||
|
||||
Any TC member or an existing captain on the **same** repo can nominate another committer
|
||||
to the captain role. To do so, they should submit a PR to this document, updating the
|
||||
**Active Project Captains** section (while maintaining the sort order) with the project
|
||||
name, the nominee's GitHub handle, and their npm username (if different).
|
||||
- Repos can have as many captains as make sense for the scope of work.
|
||||
- A TC member or an existing repo captain **on the same project** can nominate a new captain.
|
||||
Repo captains from other projects should not nominate captains for a different project.
|
||||
|
||||
The PR will require at least 2 approvals from TC members and 2 weeks hold time to allow
|
||||
for comment and/or dissent. When the PR is merged, a TC member will add them to the
|
||||
proper GitHub/npm groups.
|
||||
|
||||
### Active Projects and Captains
|
||||
|
||||
- `expressjs/badgeboard`: @wesleytodd
|
||||
- `expressjs/basic-auth-connect`: N/A
|
||||
- `expressjs/body-parser`: @wesleytodd, @jonchurch
|
||||
- `expressjs/compression`: N/A
|
||||
- `expressjs/connect-multiparty`: N/A
|
||||
- `expressjs/cookie-parser`: @wesleytodd, @UlisesGascon
|
||||
- `expressjs/cookie-session`: N/A
|
||||
- `expressjs/cors`: @jonchurch
|
||||
- `expressjs/discussions`: @wesleytodd
|
||||
- `expressjs/errorhandler`: N/A
|
||||
- `expressjs/express-paginate`: N/A
|
||||
- `expressjs/express`: @wesleytodd
|
||||
- `expressjs/expressjs.com`: @crandmck, @jonchurch
|
||||
- `expressjs/flash`: N/A
|
||||
- `expressjs/generator`: @wesleytodd
|
||||
- `expressjs/method-override`: N/A
|
||||
- `expressjs/morgan`: @jonchurch
|
||||
- `expressjs/multer`: @LinusU
|
||||
- `expressjs/response-time`: @blakeembrey
|
||||
- `expressjs/serve-favicon`: N/A
|
||||
- `expressjs/serve-index`: N/A
|
||||
- `expressjs/serve-static`: N/A
|
||||
- `expressjs/session`: N/A
|
||||
- `expressjs/statusboard`: @wesleytodd
|
||||
- `expressjs/timeout`: N/A
|
||||
- `expressjs/vhost`: N/A
|
||||
- `jshttp/accepts`: @blakeembrey
|
||||
- `jshttp/basic-auth`: @blakeembrey
|
||||
- `jshttp/compressible`: @blakeembrey
|
||||
- `jshttp/content-disposition`: @blakeembrey
|
||||
- `jshttp/content-type`: @blakeembrey
|
||||
- `jshttp/cookie`: @wesleytodd
|
||||
- `jshttp/etag`: @blakeembrey
|
||||
- `jshttp/forwarded`: @blakeembrey
|
||||
- `jshttp/fresh`: @blakeembrey
|
||||
- `jshttp/http-assert`: @wesleytodd, @jonchurch
|
||||
- `jshttp/http-errors`: @wesleytodd, @jonchurch
|
||||
- `jshttp/media-typer`: @blakeembrey
|
||||
- `jshttp/methods`: @blakeembrey
|
||||
- `jshttp/mime-db`: @blakeembrey, @UlisesGascon
|
||||
- `jshttp/mime-types`: @blakeembrey, @UlisesGascon
|
||||
- `jshttp/negotiator`: @blakeembrey
|
||||
- `jshttp/on-finished`: @wesleytodd
|
||||
- `jshttp/on-headers`: @blakeembrey
|
||||
- `jshttp/proxy-addr`: @wesleytodd
|
||||
- `jshttp/range-parser`: @blakeembrey
|
||||
- `jshttp/statuses`: @blakeembrey
|
||||
- `jshttp/type-is`: @blakeembrey
|
||||
- `jshttp/vary`: @blakeembrey
|
||||
- `pillarjs/cookies`: @blakeembrey
|
||||
- `pillarjs/csrf`: N/A
|
||||
- `pillarjs/encodeurl`: @blakeembrey
|
||||
- `pillarjs/finalhandler`: @wesleytodd
|
||||
- `pillarjs/hbs`: N/A
|
||||
- `pillarjs/multiparty`: @blakeembrey
|
||||
- `pillarjs/parseurl`: @blakeembrey
|
||||
- `pillarjs/path-to-regexp`: @blakeembrey
|
||||
- `pillarjs/request`: @wesleytodd
|
||||
- `pillarjs/resolve-path`: @blakeembrey
|
||||
- `pillarjs/router`: @blakeembrey
|
||||
- `pillarjs/send`: @blakeembrey
|
||||
- `pillarjs/understanding-csrf`: N/A
|
||||
- [`expressjs/badgeboard`](https://github.com/expressjs/badgeboard): @wesleytodd
|
||||
- [`expressjs/basic-auth-connect`](https://github.com/expressjs/basic-auth-connect): @ulisesGascon
|
||||
- [`expressjs/body-parser`](https://github.com/expressjs/body-parser): @wesleytodd, @jonchurch, @ulisesGascon
|
||||
- [`expressjs/compression`](https://github.com/expressjs/compression): @ulisesGascon
|
||||
- [`expressjs/connect-multiparty`](https://github.com/expressjs/connect-multiparty): @ulisesGascon
|
||||
- [`expressjs/cookie-parser`](https://github.com/expressjs/cookie-parser): @wesleytodd, @UlisesGascon
|
||||
- [`expressjs/cookie-session`](https://github.com/expressjs/cookie-session): @ulisesGascon
|
||||
- [`expressjs/cors`](https://github.com/expressjs/cors): @jonchurch, @ulisesGascon
|
||||
- [`expressjs/discussions`](https://github.com/expressjs/discussions): @wesleytodd
|
||||
- [`expressjs/errorhandler`](https://github.com/expressjs/errorhandler): @ulisesGascon
|
||||
- [`expressjs/express-paginate`](https://github.com/expressjs/express-paginate): @ulisesGascon
|
||||
- [`expressjs/express`](https://github.com/expressjs/express): @wesleytodd, @ulisesGascon
|
||||
- [`expressjs/expressjs.com`](https://github.com/expressjs/expressjs.com): @crandmck, @jonchurch, @bjohansebas
|
||||
- [`expressjs/flash`](https://github.com/expressjs/flash): @ulisesGascon
|
||||
- [`expressjs/generator`](https://github.com/expressjs/generator): @wesleytodd
|
||||
- [`expressjs/method-override`](https://github.com/expressjs/method-override): @ulisesGascon
|
||||
- [`expressjs/morgan`](https://github.com/expressjs/morgan): @jonchurch, @ulisesGascon
|
||||
- [`expressjs/multer`](https://github.com/expressjs/multer): @LinusU, @ulisesGascon
|
||||
- [`expressjs/response-time`](https://github.com/expressjs/response-time): @UlisesGascon
|
||||
- [`expressjs/serve-favicon`](https://github.com/expressjs/serve-favicon): @ulisesGascon
|
||||
- [`expressjs/serve-index`](https://github.com/expressjs/serve-index): @ulisesGascon
|
||||
- [`expressjs/serve-static`](https://github.com/expressjs/serve-static): @ulisesGascon
|
||||
- [`expressjs/session`](https://github.com/expressjs/session): @ulisesGascon
|
||||
- [`expressjs/statusboard`](https://github.com/expressjs/statusboard): @wesleytodd
|
||||
- [`expressjs/timeout`](https://github.com/expressjs/timeout): @ulisesGascon
|
||||
- [`expressjs/vhost`](https://github.com/expressjs/vhost): @ulisesGascon
|
||||
- [`jshttp/accepts`](https://github.com/jshttp/accepts): @blakeembrey
|
||||
- [`jshttp/basic-auth`](https://github.com/jshttp/basic-auth): @blakeembrey
|
||||
- [`jshttp/compressible`](https://github.com/jshttp/compressible): @blakeembrey
|
||||
- [`jshttp/content-disposition`](https://github.com/jshttp/content-disposition): @blakeembrey
|
||||
- [`jshttp/content-type`](https://github.com/jshttp/content-type): @blakeembrey
|
||||
- [`jshttp/cookie`](https://github.com/jshttp/cookie): @blakeembrey
|
||||
- [`jshttp/etag`](https://github.com/jshttp/etag): @blakeembrey
|
||||
- [`jshttp/forwarded`](https://github.com/jshttp/forwarded): @blakeembrey
|
||||
- [`jshttp/fresh`](https://github.com/jshttp/fresh): @blakeembrey
|
||||
- [`jshttp/http-assert`](https://github.com/jshttp/http-assert): @wesleytodd, @jonchurch, @ulisesGascon
|
||||
- [`jshttp/http-errors`](https://github.com/jshttp/http-errors): @wesleytodd, @jonchurch, @ulisesGascon
|
||||
- [`jshttp/media-typer`](https://github.com/jshttp/media-typer): @blakeembrey
|
||||
- [`jshttp/methods`](https://github.com/jshttp/methods): @blakeembrey
|
||||
- [`jshttp/mime-db`](https://github.com/jshttp/mime-db): @blakeembrey, @UlisesGascon
|
||||
- [`jshttp/mime-types`](https://github.com/jshttp/mime-types): @blakeembrey, @UlisesGascon
|
||||
- [`jshttp/negotiator`](https://github.com/jshttp/negotiator): @blakeembrey
|
||||
- [`jshttp/on-finished`](https://github.com/jshttp/on-finished): @wesleytodd, @ulisesGascon
|
||||
- [`jshttp/on-headers`](https://github.com/jshttp/on-headers): @blakeembrey
|
||||
- [`jshttp/proxy-addr`](https://github.com/jshttp/proxy-addr): @wesleytodd, @ulisesGascon
|
||||
- [`jshttp/range-parser`](https://github.com/jshttp/range-parser): @blakeembrey
|
||||
- [`jshttp/statuses`](https://github.com/jshttp/statuses): @blakeembrey
|
||||
- [`jshttp/type-is`](https://github.com/jshttp/type-is): @blakeembrey
|
||||
- [`jshttp/vary`](https://github.com/jshttp/vary): @blakeembrey
|
||||
- [`pillarjs/cookies`](https://github.com/pillarjs/cookies): @blakeembrey
|
||||
- [`pillarjs/csrf`](https://github.com/pillarjs/csrf): @ulisesGascon
|
||||
- [`pillarjs/encodeurl`](https://github.com/pillarjs/encodeurl): @blakeembrey
|
||||
- [`pillarjs/finalhandler`](https://github.com/pillarjs/finalhandler): @wesleytodd, @ulisesGascon
|
||||
- [`pillarjs/hbs`](https://github.com/pillarjs/hbs): @ulisesGascon
|
||||
- [`pillarjs/multiparty`](https://github.com/pillarjs/multiparty): @blakeembrey
|
||||
- [`pillarjs/parseurl`](https://github.com/pillarjs/parseurl): @blakeembrey
|
||||
- [`pillarjs/path-to-regexp`](https://github.com/pillarjs/path-to-regexp): @blakeembrey
|
||||
- [`pillarjs/request`](https://github.com/pillarjs/request): @wesleytodd
|
||||
- [`pillarjs/resolve-path`](https://github.com/pillarjs/resolve-path): @blakeembrey
|
||||
- [`pillarjs/router`](https://github.com/pillarjs/router): @wesleytodd, @ulisesGascon
|
||||
- [`pillarjs/send`](https://github.com/pillarjs/send): @blakeembrey
|
||||
- [`pillarjs/understanding-csrf`](https://github.com/pillarjs/understanding-csrf): @ulisesGascon
|
||||
|
||||
### Current Initiative Captains
|
||||
|
||||
- Triage team [ref](https://github.com/expressjs/discussions/issues/227): @UlisesGascon
|
||||
|
||||
## Developer's Certificate of Origin 1.1
|
||||
|
||||
```text
|
||||
By making a contribution to this project, I certify that:
|
||||
|
||||
(a) The contribution was created in whole or in part by me and I
|
||||
have the right to submit it under the open source license
|
||||
indicated in the file; or
|
||||
|
||||
(b) The contribution is based upon previous work that, to the best
|
||||
of my knowledge, is covered under an appropriate open source
|
||||
license and I have the right under that license to submit that
|
||||
work with modifications, whether created in whole or in part
|
||||
by me, under the same open source license (unless I am
|
||||
permitted to submit under a different license), as indicated
|
||||
in the file; or
|
||||
|
||||
(c) The contribution was provided directly to me by some other
|
||||
person who certified (a), (b) or (c) and I have not modified
|
||||
it.
|
||||
|
||||
(d) I understand and agree that this project and the contribution
|
||||
are public and that a record of the contribution (including all
|
||||
personal information I submit with it, including my sign-off) is
|
||||
maintained indefinitely and may be redistributed consistent with
|
||||
this project or the open source license(s) involved.
|
||||
```
|
||||
|
|
|
|||
238
History.md
238
History.md
|
|
@ -1,8 +1,244 @@
|
|||
unreleased
|
||||
========================
|
||||
|
||||
* Remove `utils-merge` dependency - use spread syntax instead
|
||||
* Remove `Object.setPrototypeOf` polyfill
|
||||
* cleanup: remove AsyncLocalStorage check from tests
|
||||
* cleanup: remove unnecessary require for global Buffer
|
||||
* perf: use loop for acceptParams
|
||||
* Replace `methods` dependency with standard library
|
||||
* refactor: prefix built-in node module imports
|
||||
* Remove unused `depd` dependency
|
||||
* Add support for `Uint8Array` in `res.send`
|
||||
* Add support for ETag option in res.sendFile
|
||||
* Extend res.links() to allow adding multiple links with the same rel
|
||||
* deps: debug@^4.4.0
|
||||
* deps: body-parser@^2.1.0
|
||||
* deps: router@^2.1.0
|
||||
* deps: nyc@^17.1.0
|
||||
* deps: mocha@^10.7.3
|
||||
* deps: marked@^15.0.3
|
||||
* deps: express-session@^1.18.1
|
||||
* deps: ejs@^3.1.10
|
||||
* deps: content-type@^1.0.5
|
||||
* deps: connect-redis@^8.0.1
|
||||
* deps: supertest@^6.3.4
|
||||
|
||||
5.0.1 / 2024-10-08
|
||||
==========
|
||||
|
||||
* deps: path-to-regexp@0.1.8
|
||||
* Update `cookie` semver lock to address [CVE-2024-47764](https://nvd.nist.gov/vuln/detail/CVE-2024-47764)
|
||||
|
||||
5.0.0 / 2024-09-10
|
||||
=========================
|
||||
* remove:
|
||||
- `path-is-absolute` dependency - use `path.isAbsolute` instead
|
||||
* breaking:
|
||||
* `res.status()` accepts only integers, and input must be greater than 99 and less than 1000
|
||||
* will throw a `RangeError: Invalid status code: ${code}. Status code must be greater than 99 and less than 1000.` for inputs outside this range
|
||||
* will throw a `TypeError: Invalid status code: ${code}. Status code must be an integer.` for non integer inputs
|
||||
* deps: send@1.0.0
|
||||
* `res.redirect('back')` and `res.location('back')` is no longer a supported magic string, explicitly use `req.get('Referrer') || '/'`.
|
||||
* change:
|
||||
- `res.clearCookie` will ignore user provided `maxAge` and `expires` options
|
||||
* deps: cookie-signature@^1.2.1
|
||||
* deps: debug@4.3.6
|
||||
* deps: merge-descriptors@^2.0.0
|
||||
* deps: serve-static@^2.1.0
|
||||
* deps: qs@6.13.0
|
||||
* deps: accepts@^2.0.0
|
||||
* deps: mime-types@^3.0.0
|
||||
- `application/javascript` => `text/javascript`
|
||||
* deps: type-is@^2.0.0
|
||||
* deps: content-disposition@^1.0.0
|
||||
* deps: finalhandler@^2.0.0
|
||||
* deps: fresh@^2.0.0
|
||||
* deps: body-parser@^2.0.1
|
||||
* deps: send@^1.1.0
|
||||
|
||||
5.0.0-beta.3 / 2024-03-25
|
||||
=========================
|
||||
|
||||
This incorporates all changes after 4.19.1 up to 4.19.2.
|
||||
|
||||
5.0.0-beta.2 / 2024-03-20
|
||||
=========================
|
||||
|
||||
This incorporates all changes after 4.17.2 up to 4.19.1.
|
||||
|
||||
5.0.0-beta.1 / 2022-02-14
|
||||
=========================
|
||||
|
||||
This is the first Express 5.0 beta release, based off 4.17.2 and includes
|
||||
changes from 5.0.0-alpha.8.
|
||||
|
||||
* change:
|
||||
- Default "query parser" setting to `'simple'`
|
||||
- Requires Node.js 4+
|
||||
- Use `mime-types` for file to content type mapping
|
||||
* deps: array-flatten@3.0.0
|
||||
* deps: body-parser@2.0.0-beta.1
|
||||
- `req.body` is no longer always initialized to `{}`
|
||||
- `urlencoded` parser now defaults `extended` to `false`
|
||||
- Use `on-finished` to determine when body read
|
||||
* deps: router@2.0.0-beta.1
|
||||
- Add new `?`, `*`, and `+` parameter modifiers
|
||||
- Internalize private `router.process_params` method
|
||||
- Matching group expressions are only RegExp syntax
|
||||
- Named matching groups no longer available by position in `req.params`
|
||||
- Regular expressions can only be used in a matching group
|
||||
- Remove `debug` dependency
|
||||
- Special `*` path segment behavior removed
|
||||
- deps: array-flatten@3.0.0
|
||||
- deps: parseurl@~1.3.3
|
||||
- deps: path-to-regexp@3.2.0
|
||||
- deps: setprototypeof@1.2.0
|
||||
* deps: send@1.0.0-beta.1
|
||||
- Change `dotfiles` option default to `'ignore'`
|
||||
- Remove `hidden` option; use `dotfiles` option instead
|
||||
- Use `mime-types` for file to content type mapping
|
||||
- deps: debug@3.1.0
|
||||
* deps: serve-static@2.0.0-beta.1
|
||||
- Change `dotfiles` option default to `'ignore'`
|
||||
- Remove `hidden` option; use `dotfiles` option instead
|
||||
- Use `mime-types` for file to content type mapping
|
||||
- Remove `express.static.mime` export; use `mime-types` package instead
|
||||
- deps: send@1.0.0-beta.1
|
||||
|
||||
5.0.0-alpha.8 / 2020-03-25
|
||||
==========================
|
||||
|
||||
This is the eighth Express 5.0 alpha release, based off 4.17.1 and includes
|
||||
changes from 5.0.0-alpha.7.
|
||||
|
||||
5.0.0-alpha.7 / 2018-10-26
|
||||
==========================
|
||||
|
||||
This is the seventh Express 5.0 alpha release, based off 4.16.4 and includes
|
||||
changes from 5.0.0-alpha.6.
|
||||
|
||||
The major change with this alpha is the basic support for returned, rejected
|
||||
Promises in the router.
|
||||
|
||||
* remove:
|
||||
- `path-to-regexp` dependency
|
||||
* deps: debug@3.1.0
|
||||
- Add `DEBUG_HIDE_DATE` environment variable
|
||||
- Change timer to per-namespace instead of global
|
||||
- Change non-TTY date format
|
||||
- Remove `DEBUG_FD` environment variable support
|
||||
- Support 256 namespace colors
|
||||
* deps: router@2.0.0-alpha.1
|
||||
- Add basic support for returned, rejected Promises
|
||||
- Fix JSDoc for `Router` constructor
|
||||
- deps: debug@3.1.0
|
||||
- deps: parseurl@~1.3.2
|
||||
- deps: setprototypeof@1.1.0
|
||||
- deps: utils-merge@1.0.1
|
||||
|
||||
5.0.0-alpha.6 / 2017-09-24
|
||||
==========================
|
||||
|
||||
This is the sixth Express 5.0 alpha release, based off 4.15.5 and includes
|
||||
changes from 5.0.0-alpha.5.
|
||||
|
||||
* remove:
|
||||
- `res.redirect(url, status)` signature - use `res.redirect(status, url)`
|
||||
- `res.send(status, body)` signature - use `res.status(status).send(body)`
|
||||
* deps: router@~1.3.1
|
||||
- deps: debug@2.6.8
|
||||
|
||||
5.0.0-alpha.5 / 2017-03-06
|
||||
==========================
|
||||
|
||||
This is the fifth Express 5.0 alpha release, based off 4.15.2 and includes
|
||||
changes from 5.0.0-alpha.4.
|
||||
|
||||
5.0.0-alpha.4 / 2017-03-01
|
||||
==========================
|
||||
|
||||
This is the fourth Express 5.0 alpha release, based off 4.15.0 and includes
|
||||
changes from 5.0.0-alpha.3.
|
||||
|
||||
* remove:
|
||||
- Remove Express 3.x middleware error stubs
|
||||
* deps: router@~1.3.0
|
||||
- Add `next("router")` to exit from router
|
||||
- Fix case where `router.use` skipped requests routes did not
|
||||
- Skip routing when `req.url` is not set
|
||||
- Use `%o` in path debug to tell types apart
|
||||
- deps: debug@2.6.1
|
||||
- deps: setprototypeof@1.0.3
|
||||
- perf: add fast match path for `*` route
|
||||
|
||||
5.0.0-alpha.3 / 2017-01-28
|
||||
==========================
|
||||
|
||||
This is the third Express 5.0 alpha release, based off 4.14.1 and includes
|
||||
changes from 5.0.0-alpha.2.
|
||||
|
||||
* remove:
|
||||
- `res.json(status, obj)` signature - use `res.status(status).json(obj)`
|
||||
- `res.jsonp(status, obj)` signature - use `res.status(status).jsonp(obj)`
|
||||
- `res.vary()` (no arguments) -- provide a field name as an argument
|
||||
* deps: array-flatten@2.1.1
|
||||
* deps: path-is-absolute@1.0.1
|
||||
* deps: router@~1.1.5
|
||||
- deps: array-flatten@2.0.1
|
||||
- deps: methods@~1.1.2
|
||||
- deps: parseurl@~1.3.1
|
||||
- deps: setprototypeof@1.0.2
|
||||
|
||||
5.0.0-alpha.2 / 2015-07-06
|
||||
==========================
|
||||
|
||||
This is the second Express 5.0 alpha release, based off 4.13.1 and includes
|
||||
changes from 5.0.0-alpha.1.
|
||||
|
||||
* remove:
|
||||
- `app.param(fn)`
|
||||
- `req.param()` -- use `req.params`, `req.body`, or `req.query` instead
|
||||
* change:
|
||||
- `res.render` callback is always async, even for sync view engines
|
||||
- The leading `:` character in `name` for `app.param(name, fn)` is no longer removed
|
||||
- Use `router` module for routing
|
||||
- Use `path-is-absolute` module for absolute path detection
|
||||
|
||||
5.0.0-alpha.1 / 2014-11-06
|
||||
==========================
|
||||
|
||||
This is the first Express 5.0 alpha release, based off 4.10.1.
|
||||
|
||||
* remove:
|
||||
- `app.del` - use `app.delete`
|
||||
- `req.acceptsCharset` - use `req.acceptsCharsets`
|
||||
- `req.acceptsEncoding` - use `req.acceptsEncodings`
|
||||
- `req.acceptsLanguage` - use `req.acceptsLanguages`
|
||||
- `res.json(obj, status)` signature - use `res.json(status, obj)`
|
||||
- `res.jsonp(obj, status)` signature - use `res.jsonp(status, obj)`
|
||||
- `res.send(body, status)` signature - use `res.send(status, body)`
|
||||
- `res.send(status)` signature - use `res.sendStatus(status)`
|
||||
- `res.sendfile` - use `res.sendFile` instead
|
||||
- `express.query` middleware
|
||||
* change:
|
||||
- `req.host` now returns host (`hostname:port`) - use `req.hostname` for only hostname
|
||||
- `req.query` is now a getter instead of a plain property
|
||||
* add:
|
||||
- `app.router` is a reference to the base router
|
||||
|
||||
4.20.0 / 2024-09-10
|
||||
==========
|
||||
* deps: serve-static@0.16.0
|
||||
* Remove link renderization in html while redirecting
|
||||
* deps: send@0.19.0
|
||||
* Remove link renderization in html while redirecting
|
||||
* deps: body-parser@0.6.0
|
||||
* add `depth` option to customize the depth level in the parser
|
||||
* IMPORTANT: The default `depth` level for parsing URL-encoded data is now `32` (previously was `Infinity`)
|
||||
* Remove link renderization in html while using `res.redirect`
|
||||
* deps: path-to-regexp@0.1.10
|
||||
- Adds support for named matching groups in the routes using a regex
|
||||
- Adds backtracking protection to parameters without regexes defined
|
||||
* deps: encodeurl@~2.0.0
|
||||
- Removes encoding of `\`, `|`, and `^` to align better with URL spec
|
||||
* Deprecate passing `options.maxAge` and `options.expires` to `res.clearCookie`
|
||||
|
|
|
|||
86
Readme.md
86
Readme.md
|
|
@ -1,6 +1,6 @@
|
|||
[](http://expressjs.com/)
|
||||
[](https://expressjs.com/)
|
||||
|
||||
**Fast, unopinionated, minimalist web framework for [Node.js](http://nodejs.org).**
|
||||
**Fast, unopinionated, minimalist web framework for [Node.js](https://nodejs.org).**
|
||||
|
||||
**This project has a [Code of Conduct][].**
|
||||
|
||||
|
|
@ -20,16 +20,16 @@
|
|||
|
||||
|
||||
[![NPM Version][npm-version-image]][npm-url]
|
||||
[![NPM Install Size][npm-install-size-image]][npm-install-size-url]
|
||||
[![NPM Downloads][npm-downloads-image]][npm-downloads-url]
|
||||
[![OpenSSF Scorecard Badge][ossf-scorecard-badge]][ossf-scorecard-visualizer]
|
||||
|
||||
|
||||
```js
|
||||
const express = require('express')
|
||||
import express from 'express'
|
||||
|
||||
const app = express()
|
||||
|
||||
app.get('/', function (req, res) {
|
||||
app.get('/', (req, res) => {
|
||||
res.send('Hello World')
|
||||
})
|
||||
|
||||
|
|
@ -42,7 +42,7 @@ This is a [Node.js](https://nodejs.org/en/) module available through the
|
|||
[npm registry](https://www.npmjs.com/).
|
||||
|
||||
Before installing, [download and install Node.js](https://nodejs.org/en/download/).
|
||||
Node.js 0.10 or higher is required.
|
||||
Node.js 18 or higher is required.
|
||||
|
||||
If this is a brand new project, make sure to create a `package.json` first with
|
||||
the [`npm init` command](https://docs.npmjs.com/creating-a-package-json-file).
|
||||
|
|
@ -50,11 +50,11 @@ the [`npm init` command](https://docs.npmjs.com/creating-a-package-json-file).
|
|||
Installation is done using the
|
||||
[`npm install` command](https://docs.npmjs.com/getting-started/installing-npm-packages-locally):
|
||||
|
||||
```console
|
||||
$ npm install express
|
||||
```bash
|
||||
npm install express
|
||||
```
|
||||
|
||||
Follow [our installing guide](http://expressjs.com/en/starter/installing.html)
|
||||
Follow [our installing guide](https://expressjs.com/en/starter/installing.html)
|
||||
for more information.
|
||||
|
||||
## Features
|
||||
|
|
@ -69,14 +69,11 @@ for more information.
|
|||
|
||||
## Docs & Community
|
||||
|
||||
* [Website and Documentation](http://expressjs.com/) - [[website repo](https://github.com/expressjs/expressjs.com)]
|
||||
* [#express](https://web.libera.chat/#express) on [Libera Chat](https://libera.chat) IRC
|
||||
* [Website and Documentation](https://expressjs.com/) - [[website repo](https://github.com/expressjs/expressjs.com)]
|
||||
* [GitHub Organization](https://github.com/expressjs) for Official Middleware & Modules
|
||||
* Visit the [Wiki](https://github.com/expressjs/express/wiki)
|
||||
* [Google Group](https://groups.google.com/group/express-js) for discussion
|
||||
* [Gitter](https://gitter.im/expressjs/express) for support and discussion
|
||||
* [Github Discussions](https://github.com/expressjs/discussions) for discussion on the development and usage of Express
|
||||
|
||||
**PROTIP** Be sure to read [Migrating from 3.x to 4.x](https://github.com/expressjs/express/wiki/Migrating-from-3.x-to-4.x) as well as [New features in 4.x](https://github.com/expressjs/express/wiki/New-features-in-4.x).
|
||||
**PROTIP** Be sure to read the [migration guide to v5](https://expressjs.com/en/guide/migrating-5)
|
||||
|
||||
## Quick Start
|
||||
|
||||
|
|
@ -84,26 +81,26 @@ for more information.
|
|||
|
||||
Install the executable. The executable's major version will match Express's:
|
||||
|
||||
```console
|
||||
$ npm install -g express-generator@4
|
||||
```bash
|
||||
npm install -g express-generator@4
|
||||
```
|
||||
|
||||
Create the app:
|
||||
|
||||
```console
|
||||
$ express /tmp/foo && cd /tmp/foo
|
||||
```bash
|
||||
express /tmp/foo && cd /tmp/foo
|
||||
```
|
||||
|
||||
Install dependencies:
|
||||
|
||||
```console
|
||||
$ npm install
|
||||
```bash
|
||||
npm install
|
||||
```
|
||||
|
||||
Start the server:
|
||||
|
||||
```console
|
||||
$ npm start
|
||||
```bash
|
||||
npm start
|
||||
```
|
||||
|
||||
View the website at: http://localhost:3000
|
||||
|
|
@ -115,29 +112,32 @@ $ npm start
|
|||
HTTP APIs.
|
||||
|
||||
Express does not force you to use any specific ORM or template engine. With support for over
|
||||
14 template engines via [Consolidate.js](https://github.com/tj/consolidate.js),
|
||||
14 template engines via [@ladjs/consolidate](https://github.com/ladjs/consolidate),
|
||||
you can quickly craft your perfect framework.
|
||||
|
||||
## Examples
|
||||
|
||||
To view the examples, clone the Express repo and install the dependencies:
|
||||
To view the examples, clone the Express repository:
|
||||
|
||||
```console
|
||||
$ git clone https://github.com/expressjs/express.git --depth 1
|
||||
$ cd express
|
||||
$ npm install
|
||||
```bash
|
||||
git clone https://github.com/expressjs/express.git --depth 1 && cd express
|
||||
```
|
||||
|
||||
Then install the dependencies:
|
||||
|
||||
```bash
|
||||
npm install
|
||||
```
|
||||
|
||||
Then run whichever example you want:
|
||||
|
||||
```console
|
||||
$ node examples/content-negotiation
|
||||
```bash
|
||||
node examples/content-negotiation
|
||||
```
|
||||
|
||||
## Contributing
|
||||
|
||||
[![Linux Build][github-actions-ci-image]][github-actions-ci-url]
|
||||
[![Windows Build][appveyor-image]][appveyor-url]
|
||||
[![Test Coverage][coveralls-image]][coveralls-url]
|
||||
|
||||
The Express.js project welcomes all constructive contributions. Contributions take many forms,
|
||||
|
|
@ -152,11 +152,16 @@ If you discover a security vulnerability in Express, please see [Security Polici
|
|||
|
||||
### Running Tests
|
||||
|
||||
To run the test suite, first install the dependencies, then run `npm test`:
|
||||
To run the test suite, first install the dependencies:
|
||||
|
||||
```console
|
||||
$ npm install
|
||||
$ npm test
|
||||
```bash
|
||||
npm install
|
||||
```
|
||||
|
||||
Then run `npm test`:
|
||||
|
||||
```bash
|
||||
npm test
|
||||
```
|
||||
|
||||
## People
|
||||
|
|
@ -192,6 +197,7 @@ The original author of Express is [TJ Holowaychuk](https://github.com/tj)
|
|||
### Triagers
|
||||
|
||||
* [aravindvnair99](https://github.com/aravindvnair99) - **Aravind Nair**
|
||||
* [bjohansebas](https://github.com/bjohansebas) - **Sebastian Beltran**
|
||||
* [carpasse](https://github.com/carpasse) - **Carlos Serrano**
|
||||
* [CBID2](https://github.com/CBID2) - **Christine Belzie**
|
||||
* [enyoghasim](https://github.com/enyoghasim) - **David Enyoghasim**
|
||||
|
|
@ -203,7 +209,9 @@ The original author of Express is [TJ Holowaychuk](https://github.com/tj)
|
|||
* [dakshkhetan](https://github.com/dakshkhetan) - **Daksh Khetan** (he/him)
|
||||
* [lucasraziel](https://github.com/lucasraziel) - **Lucas Soares Do Rego**
|
||||
* [IamLizu](https://github.com/IamLizu) - **S M Mahmudul Hasan** (he/him)
|
||||
* [Phillip9587](https://github.com/Phillip9587) - **Phillip Barta**
|
||||
* [Sushmeet](https://github.com/Sushmeet) - **Sushmeet Sunger**
|
||||
* [rxmarbles](https://github.com/rxmarbles) **Rick Markins** (He/him)
|
||||
|
||||
<details>
|
||||
<summary>Triagers emeriti members</summary>
|
||||
|
|
@ -243,16 +251,12 @@ The original author of Express is [TJ Holowaychuk](https://github.com/tj)
|
|||
|
||||
[MIT](LICENSE)
|
||||
|
||||
[appveyor-image]: https://badgen.net/appveyor/ci/dougwilson/express/master?label=windows
|
||||
[appveyor-url]: https://ci.appveyor.com/project/dougwilson/express
|
||||
[coveralls-image]: https://badgen.net/coveralls/c/github/expressjs/express/master
|
||||
[coveralls-url]: https://coveralls.io/r/expressjs/express?branch=master
|
||||
[github-actions-ci-image]: https://badgen.net/github/checks/expressjs/express/master?label=linux
|
||||
[github-actions-ci-image]: https://badgen.net/github/checks/expressjs/express/master?label=CI
|
||||
[github-actions-ci-url]: https://github.com/expressjs/express/actions/workflows/ci.yml
|
||||
[npm-downloads-image]: https://badgen.net/npm/dm/express
|
||||
[npm-downloads-url]: https://npmcharts.com/compare/express?minimal=true
|
||||
[npm-install-size-image]: https://badgen.net/packagephobia/install/express
|
||||
[npm-install-size-url]: https://packagephobia.com/result?p=express
|
||||
[npm-url]: https://npmjs.org/package/express
|
||||
[npm-version-image]: https://badgen.net/npm/v/express
|
||||
[ossf-scorecard-badge]: https://api.scorecard.dev/projects/github.com/expressjs/express/badge
|
||||
|
|
|
|||
|
|
@ -31,7 +31,7 @@ Before publishing, the following preconditions should be met:
|
|||
below) will exist documenting:
|
||||
- the proposed changes
|
||||
- the type of release: patch, minor or major
|
||||
- the version number (according to semantic versioning - http://semver.org)
|
||||
- the version number (according to semantic versioning - https://semver.org)
|
||||
- The proposed changes should be complete.
|
||||
|
||||
There are two main release flows: patch and non-patch.
|
||||
|
|
@ -129,9 +129,10 @@ $ git merge --ff-only <proposal-branch>
|
|||
<release-branch> - see "Release branch" of "Branches" above.
|
||||
<proposal-branch> - see "Proposal branch" of "Non-patch flow" above.
|
||||
|
||||
**NOTE:** You may need to rebase the proposal branch to allow a fast-forward
|
||||
merge. Using a fast-forward merge keeps the history clean as it does
|
||||
not introduce merge commits.
|
||||
> [!NOTE]
|
||||
> You may need to rebase the proposal branch to allow a fast-forward
|
||||
> merge. Using a fast-forward merge keeps the history clean as it does
|
||||
> not introduce merge commits.
|
||||
|
||||
### Step 3. Update the History.md and package.json to the new version number
|
||||
|
||||
|
|
@ -189,11 +190,13 @@ $ npm login <npm-username>
|
|||
$ npm publish
|
||||
```
|
||||
|
||||
**NOTE:** The version number to publish will be picked up automatically from
|
||||
package.json.
|
||||
> [!NOTE]
|
||||
> The version number to publish will be picked up automatically from
|
||||
> package.json.
|
||||
|
||||
### Step 7. Update documentation website
|
||||
|
||||
The documentation website https://expressjs.com/ documents the current release version in various places. For a new release:
|
||||
1. Change the value of `current_version` in https://github.com/expressjs/expressjs.com/blob/gh-pages/_data/express.yml to match the latest version number.
|
||||
2. Add a new section to the change log. For example, for a 4.x release, https://github.com/expressjs/expressjs.com/blob/gh-pages/en/changelog/4x.md,
|
||||
The documentation website https://expressjs.com/ documents the current release version in various places. To update these, follow these steps:
|
||||
|
||||
1. Manually run the [`Update External Docs` workflow](https://github.com/expressjs/expressjs.com/actions/workflows/update-external-docs.yml) in expressjs.com repository.
|
||||
2. Add a new section to the [changelog](https://github.com/expressjs/expressjs.com/blob/gh-pages/en/changelog/index.md) in the expressjs.com website.
|
||||
|
|
|
|||
|
|
@ -14,7 +14,7 @@ Thank you for improving the security of Express. We appreciate your efforts and
|
|||
responsible disclosure and will make every effort to acknowledge your
|
||||
contributions.
|
||||
|
||||
Report security bugs by emailing the lead maintainer in the Readme.md file.
|
||||
Report security bugs by emailing `express-security@lists.openjsf.org`.
|
||||
|
||||
To ensure the timely response to your report, please ensure that the entirety
|
||||
of the report is contained within the email body and not solely behind a web
|
||||
|
|
|
|||
|
|
@ -68,3 +68,5 @@ If you have questions feel free to reach out to any of the TC members.
|
|||
- For recurring issues, it is helpful to create functional examples to demonstrate (publish as gists or a repo)
|
||||
- Review and identify the maintainers. If necessary, at-mention one or more of them if you are unsure what to do
|
||||
- Make sure all your interactions are professional, welcoming, and respectful to the parties involved.
|
||||
- When an issue refers to security concerns, responsibility is delegated to the repository captain or the security group in any public communication.
|
||||
- If an issue has been open for a long time, the person in charge should be contacted internally through the private Slack chat.
|
||||
113
appveyor.yml
113
appveyor.yml
|
|
@ -1,113 +0,0 @@
|
|||
environment:
|
||||
matrix:
|
||||
- nodejs_version: "0.10"
|
||||
- nodejs_version: "0.12"
|
||||
- nodejs_version: "1.8"
|
||||
- nodejs_version: "2.5"
|
||||
- nodejs_version: "3.3"
|
||||
- nodejs_version: "4.9"
|
||||
- nodejs_version: "5.12"
|
||||
- nodejs_version: "6.17"
|
||||
- nodejs_version: "7.10"
|
||||
- nodejs_version: "8.17"
|
||||
- nodejs_version: "9.11"
|
||||
- nodejs_version: "10.24"
|
||||
- nodejs_version: "11.15"
|
||||
- nodejs_version: "12.22"
|
||||
- nodejs_version: "13.14"
|
||||
- nodejs_version: "14.20"
|
||||
- nodejs_version: "15.14"
|
||||
- nodejs_version: "16.20"
|
||||
- nodejs_version: "17.9"
|
||||
- nodejs_version: "18.19"
|
||||
- nodejs_version: "19.9"
|
||||
- nodejs_version: "20.11"
|
||||
- nodejs_version: "21.6"
|
||||
- nodejs_version: "22.0"
|
||||
cache:
|
||||
- node_modules
|
||||
install:
|
||||
# Install Node.js
|
||||
- ps: >-
|
||||
try { Install-Product node $env:nodejs_version -ErrorAction Stop }
|
||||
catch { Update-NodeJsInstallation (Get-NodeJsLatestBuild $env:nodejs_version) x64 }
|
||||
# Configure npm
|
||||
- ps: |
|
||||
npm config set loglevel error
|
||||
if ((npm config get package-lock) -eq "true") {
|
||||
npm config set package-lock false
|
||||
} else {
|
||||
npm config set shrinkwrap false
|
||||
}
|
||||
# Remove all non-test dependencies
|
||||
- ps: |
|
||||
# Remove example dependencies
|
||||
npm rm --silent --save-dev connect-redis
|
||||
# Remove lint dependencies
|
||||
cmd.exe /c "node -pe `"Object.keys(require('./package').devDependencies).join('\n')`"" | `
|
||||
sls "^eslint(-|$)" | `
|
||||
%{ npm rm --silent --save-dev $_ }
|
||||
# Setup Node.js version-specific dependencies
|
||||
- ps: |
|
||||
# mocha for testing
|
||||
# - use 3.x for Node.js < 4
|
||||
# - use 5.x for Node.js < 6
|
||||
# - use 6.x for Node.js < 8
|
||||
# - use 7.x for Node.js < 10
|
||||
# - use 8.x for Node.js < 12
|
||||
# - use 9.x for Node.js < 14
|
||||
if ([int]$env:nodejs_version.split(".")[0] -lt 4) {
|
||||
npm install --silent --save-dev mocha@3.5.3
|
||||
} elseif ([int]$env:nodejs_version.split(".")[0] -lt 6) {
|
||||
npm install --silent --save-dev mocha@5.2.0
|
||||
} elseif ([int]$env:nodejs_version.split(".")[0] -lt 8) {
|
||||
npm install --silent --save-dev mocha@6.2.2
|
||||
} elseif ([int]$env:nodejs_version.split(".")[0] -lt 10) {
|
||||
npm install --silent --save-dev mocha@7.2.0
|
||||
} elseif ([int]$env:nodejs_version.split(".")[0] -lt 12) {
|
||||
npm install --silent --save-dev mocha@8.4.0
|
||||
} elseif ([int]$env:nodejs_version.split(".")[0] -lt 14) {
|
||||
npm install --silent --save-dev mocha@9.2.2
|
||||
}
|
||||
- ps: |
|
||||
# nyc for test coverage
|
||||
# - use 10.3.2 for Node.js < 4
|
||||
# - use 11.9.0 for Node.js < 6
|
||||
# - use 14.1.1 for Node.js < 10
|
||||
if ([int]$env:nodejs_version.split(".")[0] -lt 4) {
|
||||
npm install --silent --save-dev nyc@10.3.2
|
||||
} elseif ([int]$env:nodejs_version.split(".")[0] -lt 6) {
|
||||
npm install --silent --save-dev nyc@11.9.0
|
||||
} elseif ([int]$env:nodejs_version.split(".")[0] -lt 10) {
|
||||
npm install --silent --save-dev nyc@14.1.1
|
||||
}
|
||||
- ps: |
|
||||
# supertest for http calls
|
||||
# - use 2.0.0 for Node.js < 4
|
||||
# - use 3.4.2 for Node.js < 7
|
||||
# - use 6.1.6 for Node.js < 8
|
||||
if ([int]$env:nodejs_version.split(".")[0] -lt 4) {
|
||||
npm install --silent --save-dev supertest@2.0.0
|
||||
} elseif ([int]$env:nodejs_version.split(".")[0] -lt 7) {
|
||||
npm install --silent --save-dev supertest@3.4.2
|
||||
} elseif ([int]$env:nodejs_version.split(".")[0] -lt 8) {
|
||||
npm install --silent --save-dev supertest@6.1.6
|
||||
}
|
||||
# Update Node.js modules
|
||||
- ps: |
|
||||
# Prune & rebuild node_modules
|
||||
if (Test-Path -Path node_modules) {
|
||||
npm prune
|
||||
npm rebuild
|
||||
}
|
||||
# Install Node.js modules
|
||||
- npm install
|
||||
build: off
|
||||
test_script:
|
||||
# Output version data
|
||||
- ps: |
|
||||
node --version
|
||||
npm --version
|
||||
# Run test script
|
||||
- npm run test-ci
|
||||
version: "{build}"
|
||||
|
|
@ -6,7 +6,7 @@
|
|||
|
||||
var express = require('../..');
|
||||
var hash = require('pbkdf2-password')()
|
||||
var path = require('path');
|
||||
var path = require('node:path');
|
||||
var session = require('express-session');
|
||||
|
||||
var app = module.exports = express();
|
||||
|
|
@ -18,7 +18,7 @@ app.set('views', path.join(__dirname, 'views'));
|
|||
|
||||
// middleware
|
||||
|
||||
app.use(express.urlencoded({ extended: false }))
|
||||
app.use(express.urlencoded())
|
||||
app.use(session({
|
||||
resave: false, // don't save session if unmodified
|
||||
saveUninitialized: false, // don't create session until something stored
|
||||
|
|
@ -102,6 +102,7 @@ app.get('/login', function(req, res){
|
|||
});
|
||||
|
||||
app.post('/login', function (req, res, next) {
|
||||
if (!req.body) return res.sendStatus(400)
|
||||
authenticate(req.body.username, req.body.password, function(err, user){
|
||||
if (err) return next(err)
|
||||
if (user) {
|
||||
|
|
@ -115,7 +116,7 @@ app.post('/login', function (req, res, next) {
|
|||
req.session.success = 'Authenticated as ' + user.name
|
||||
+ ' click to <a href="/logout">logout</a>. '
|
||||
+ ' You may now access <a href="/restricted">/restricted</a>.';
|
||||
res.redirect('back');
|
||||
res.redirect(req.get('Referrer') || '/');
|
||||
});
|
||||
} else {
|
||||
req.session.error = 'Authentication failed, please check your '
|
||||
|
|
|
|||
|
|
@ -10,7 +10,7 @@
|
|||
font: 13px Helvetica, Arial, sans-serif;
|
||||
}
|
||||
.error {
|
||||
color: red
|
||||
color: red;
|
||||
}
|
||||
.success {
|
||||
color: green;
|
||||
|
|
|
|||
|
|
@ -19,7 +19,7 @@ if (process.env.NODE_ENV !== 'test') app.use(logger(':method :url'))
|
|||
app.use(cookieParser('my secret here'));
|
||||
|
||||
// parses x-www-form-urlencoded
|
||||
app.use(express.urlencoded({ extended: false }))
|
||||
app.use(express.urlencoded())
|
||||
|
||||
app.get('/', function(req, res){
|
||||
if (req.cookies.remember) {
|
||||
|
|
@ -33,13 +33,17 @@ app.get('/', function(req, res){
|
|||
|
||||
app.get('/forget', function(req, res){
|
||||
res.clearCookie('remember');
|
||||
res.redirect('back');
|
||||
res.redirect(req.get('Referrer') || '/');
|
||||
});
|
||||
|
||||
app.post('/', function(req, res){
|
||||
var minute = 60000;
|
||||
if (req.body.remember) res.cookie('remember', 1, { maxAge: minute });
|
||||
res.redirect('back');
|
||||
|
||||
if (req.body && req.body.remember) {
|
||||
res.cookie('remember', 1, { maxAge: minute })
|
||||
}
|
||||
|
||||
res.redirect(req.get('Referrer') || '/');
|
||||
});
|
||||
|
||||
/* istanbul ignore next */
|
||||
|
|
|
|||
|
|
@ -5,7 +5,7 @@
|
|||
*/
|
||||
|
||||
var express = require('../../');
|
||||
var path = require('path');
|
||||
var path = require('node:path');
|
||||
|
||||
var app = module.exports = express();
|
||||
|
||||
|
|
@ -23,8 +23,8 @@ app.get('/', function(req, res){
|
|||
|
||||
// /files/* is accessed via req.params[0]
|
||||
// but here we name it :file
|
||||
app.get('/files/:file(*)', function(req, res, next){
|
||||
res.download(req.params.file, { root: FILES_DIR }, function (err) {
|
||||
app.get('/files/*file', function (req, res, next) {
|
||||
res.download(req.params.file.join('/'), { root: FILES_DIR }, function (err) {
|
||||
if (!err) return; // file sent
|
||||
if (err.status !== 404) return next(err); // non-404 error
|
||||
// file for download not found
|
||||
|
|
|
|||
|
|
@ -5,7 +5,7 @@
|
|||
*/
|
||||
|
||||
var express = require('../../');
|
||||
var path = require('path');
|
||||
var path = require('node:path');
|
||||
|
||||
var app = module.exports = express();
|
||||
|
||||
|
|
|
|||
|
|
@ -5,7 +5,7 @@
|
|||
*/
|
||||
|
||||
var express = require('../../');
|
||||
var path = require('path');
|
||||
var path = require('node:path');
|
||||
var app = module.exports = express();
|
||||
var logger = require('morgan');
|
||||
var silent = process.env.NODE_ENV === 'test'
|
||||
|
|
|
|||
|
|
@ -6,9 +6,9 @@
|
|||
|
||||
var escapeHtml = require('escape-html');
|
||||
var express = require('../..');
|
||||
var fs = require('fs');
|
||||
var fs = require('node:fs');
|
||||
var marked = require('marked');
|
||||
var path = require('path');
|
||||
var path = require('node:path');
|
||||
|
||||
var app = module.exports = express();
|
||||
|
||||
|
|
|
|||
|
|
@ -6,7 +6,7 @@
|
|||
|
||||
var express = require('../..');
|
||||
var logger = require('morgan');
|
||||
var path = require('path');
|
||||
var path = require('node:path');
|
||||
var session = require('express-session');
|
||||
var methodOverride = require('method-override');
|
||||
|
||||
|
|
|
|||
|
|
@ -5,8 +5,8 @@
|
|||
*/
|
||||
|
||||
var express = require('../../..');
|
||||
var fs = require('fs');
|
||||
var path = require('path');
|
||||
var fs = require('node:fs');
|
||||
var path = require('node:path');
|
||||
|
||||
module.exports = function(parent, options){
|
||||
var dir = path.join(__dirname, '..', 'controllers');
|
||||
|
|
|
|||
|
|
@ -32,7 +32,8 @@ app.param(['to', 'from'], function(req, res, next, num, name){
|
|||
// Load user by id
|
||||
|
||||
app.param('user', function(req, res, next, id){
|
||||
if (req.user = users[id]) {
|
||||
req.user = users[id]
|
||||
if (req.user) {
|
||||
next();
|
||||
} else {
|
||||
next(createError(404, 'failed to find user'));
|
||||
|
|
|
|||
|
|
@ -12,7 +12,7 @@ var app = module.exports = express();
|
|||
|
||||
app.resource = function(path, obj) {
|
||||
this.get(path, obj.index);
|
||||
this.get(path + '/:a..:b.:format?', function(req, res){
|
||||
this.get(path + '/:a..:b{.:format}', function(req, res){
|
||||
var a = parseInt(req.params.a, 10);
|
||||
var b = parseInt(req.params.b, 10);
|
||||
var format = req.params.format;
|
||||
|
|
|
|||
|
|
@ -5,7 +5,7 @@
|
|||
*/
|
||||
|
||||
var express = require('../..');
|
||||
var path = require('path');
|
||||
var path = require('node:path');
|
||||
var app = express();
|
||||
var logger = require('morgan');
|
||||
var cookieParser = require('cookie-parser');
|
||||
|
|
@ -38,7 +38,7 @@ app.get('/', site.index);
|
|||
// User
|
||||
|
||||
app.get('/users', user.list);
|
||||
app.all('/user/:id/:op?', user.load);
|
||||
app.all('/user/:id{/:op}', user.load);
|
||||
app.get('/user/:id', user.view);
|
||||
app.get('/user/:id/view', user.view);
|
||||
app.get('/user/:id/edit', user.edit);
|
||||
|
|
|
|||
|
|
@ -43,5 +43,5 @@ exports.update = function(req, res){
|
|||
var user = req.body.user;
|
||||
req.user.name = user.name;
|
||||
req.user.email = user.email;
|
||||
res.redirect('back');
|
||||
res.redirect(req.get('Referrer') || '/');
|
||||
};
|
||||
|
|
|
|||
|
|
@ -12,7 +12,7 @@
|
|||
*/
|
||||
|
||||
var express = require('../..');
|
||||
var path = require('path');
|
||||
var path = require('node:path');
|
||||
var redis = require('redis');
|
||||
|
||||
var db = redis.createClient();
|
||||
|
|
@ -35,10 +35,10 @@ db.sadd('cat', 'luna');
|
|||
* GET search for :query.
|
||||
*/
|
||||
|
||||
app.get('/search/:query?', function(req, res){
|
||||
app.get('/search/:query?', function(req, res, next){
|
||||
var query = req.params.query;
|
||||
db.smembers(query, function(err, vals){
|
||||
if (err) return res.send(500);
|
||||
if (err) return next(err);
|
||||
res.send(vals);
|
||||
});
|
||||
});
|
||||
|
|
|
|||
|
|
@ -6,7 +6,7 @@
|
|||
|
||||
var express = require('../..');
|
||||
var logger = require('morgan');
|
||||
var path = require('path');
|
||||
var path = require('node:path');
|
||||
var app = express();
|
||||
|
||||
// log requests
|
||||
|
|
|
|||
|
|
@ -4,8 +4,8 @@
|
|||
* Module dependencies.
|
||||
*/
|
||||
|
||||
var https = require('https');
|
||||
var path = require('path');
|
||||
var https = require('node:https');
|
||||
var path = require('node:path');
|
||||
var extname = path.extname;
|
||||
|
||||
/**
|
||||
|
|
|
|||
|
|
@ -5,7 +5,7 @@
|
|||
*/
|
||||
|
||||
var express = require('../..');
|
||||
var path = require('path');
|
||||
var path = require('node:path');
|
||||
var User = require('./user');
|
||||
var app = express();
|
||||
|
||||
|
|
|
|||
|
|
@ -14,29 +14,24 @@
|
|||
*/
|
||||
|
||||
var finalhandler = require('finalhandler');
|
||||
var Router = require('./router');
|
||||
var methods = require('methods');
|
||||
var middleware = require('./middleware/init');
|
||||
var query = require('./middleware/query');
|
||||
var debug = require('debug')('express:application');
|
||||
var View = require('./view');
|
||||
var http = require('http');
|
||||
var http = require('node:http');
|
||||
var methods = require('./utils').methods;
|
||||
var compileETag = require('./utils').compileETag;
|
||||
var compileQueryParser = require('./utils').compileQueryParser;
|
||||
var compileTrust = require('./utils').compileTrust;
|
||||
var deprecate = require('depd')('express');
|
||||
var flatten = require('array-flatten');
|
||||
var merge = require('utils-merge');
|
||||
var resolve = require('path').resolve;
|
||||
var setPrototypeOf = require('setprototypeof')
|
||||
var resolve = require('node:path').resolve;
|
||||
var once = require('once')
|
||||
var Router = require('router');
|
||||
|
||||
/**
|
||||
* Module variables.
|
||||
* @private
|
||||
*/
|
||||
|
||||
var hasOwnProperty = Object.prototype.hasOwnProperty
|
||||
var slice = Array.prototype.slice;
|
||||
var flatten = Array.prototype.flat;
|
||||
|
||||
/**
|
||||
* Application prototype.
|
||||
|
|
@ -62,11 +57,29 @@ var trustProxyDefaultSymbol = '@@symbol:trust_proxy_default';
|
|||
*/
|
||||
|
||||
app.init = function init() {
|
||||
this.cache = {};
|
||||
this.engines = {};
|
||||
this.settings = {};
|
||||
var router = null;
|
||||
|
||||
this.cache = Object.create(null);
|
||||
this.engines = Object.create(null);
|
||||
this.settings = Object.create(null);
|
||||
|
||||
this.defaultConfiguration();
|
||||
|
||||
// Setup getting to lazily add base router
|
||||
Object.defineProperty(this, 'router', {
|
||||
configurable: true,
|
||||
enumerable: true,
|
||||
get: function getrouter() {
|
||||
if (router === null) {
|
||||
router = new Router({
|
||||
caseSensitive: this.enabled('case sensitive routing'),
|
||||
strict: this.enabled('strict routing')
|
||||
});
|
||||
}
|
||||
|
||||
return router;
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
|
|
@ -81,7 +94,7 @@ app.defaultConfiguration = function defaultConfiguration() {
|
|||
this.enable('x-powered-by');
|
||||
this.set('etag', 'weak');
|
||||
this.set('env', env);
|
||||
this.set('query parser', 'extended');
|
||||
this.set('query parser', 'simple')
|
||||
this.set('subdomain offset', 2);
|
||||
this.set('trust proxy', false);
|
||||
|
||||
|
|
@ -102,10 +115,10 @@ app.defaultConfiguration = function defaultConfiguration() {
|
|||
}
|
||||
|
||||
// inherit protos
|
||||
setPrototypeOf(this.request, parent.request)
|
||||
setPrototypeOf(this.response, parent.response)
|
||||
setPrototypeOf(this.engines, parent.engines)
|
||||
setPrototypeOf(this.settings, parent.settings)
|
||||
Object.setPrototypeOf(this.request, parent.request)
|
||||
Object.setPrototypeOf(this.response, parent.response)
|
||||
Object.setPrototypeOf(this.engines, parent.engines)
|
||||
Object.setPrototypeOf(this.settings, parent.settings)
|
||||
});
|
||||
|
||||
// setup locals
|
||||
|
|
@ -125,32 +138,6 @@ app.defaultConfiguration = function defaultConfiguration() {
|
|||
if (env === 'production') {
|
||||
this.enable('view cache');
|
||||
}
|
||||
|
||||
Object.defineProperty(this, 'router', {
|
||||
get: function() {
|
||||
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.');
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* lazily adds the base router if it has not yet been added.
|
||||
*
|
||||
* We cannot add the base router in the defaultConfiguration because
|
||||
* it reads app settings which might be set after that has run.
|
||||
*
|
||||
* @private
|
||||
*/
|
||||
app.lazyrouter = function lazyrouter() {
|
||||
if (!this._router) {
|
||||
this._router = new Router({
|
||||
caseSensitive: this.enabled('case sensitive routing'),
|
||||
strict: this.enabled('strict routing')
|
||||
});
|
||||
|
||||
this._router.use(query(this.get('query parser fn')));
|
||||
this._router.use(middleware.init(this));
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
|
|
@ -163,22 +150,31 @@ app.lazyrouter = function lazyrouter() {
|
|||
*/
|
||||
|
||||
app.handle = function handle(req, res, callback) {
|
||||
var router = this._router;
|
||||
|
||||
// final handler
|
||||
var done = callback || finalhandler(req, res, {
|
||||
env: this.get('env'),
|
||||
onerror: logerror.bind(this)
|
||||
});
|
||||
|
||||
// no routes
|
||||
if (!router) {
|
||||
debug('no routes defined on app');
|
||||
done();
|
||||
return;
|
||||
// set powered by header
|
||||
if (this.enabled('x-powered-by')) {
|
||||
res.setHeader('X-Powered-By', 'Express');
|
||||
}
|
||||
|
||||
router.handle(req, res, done);
|
||||
// set circular references
|
||||
req.res = res;
|
||||
res.req = req;
|
||||
|
||||
// alter the prototypes
|
||||
Object.setPrototypeOf(req, this.request)
|
||||
Object.setPrototypeOf(res, this.response)
|
||||
|
||||
// setup locals
|
||||
if (!res.locals) {
|
||||
res.locals = Object.create(null);
|
||||
}
|
||||
|
||||
this.router.handle(req, res, done);
|
||||
};
|
||||
|
||||
/**
|
||||
|
|
@ -211,15 +207,14 @@ app.use = function use(fn) {
|
|||
}
|
||||
}
|
||||
|
||||
var fns = flatten(slice.call(arguments, offset));
|
||||
var fns = flatten.call(slice.call(arguments, offset), Infinity);
|
||||
|
||||
if (fns.length === 0) {
|
||||
throw new TypeError('app.use() requires a middleware function')
|
||||
}
|
||||
|
||||
// setup router
|
||||
this.lazyrouter();
|
||||
var router = this._router;
|
||||
// get router
|
||||
var router = this.router;
|
||||
|
||||
fns.forEach(function (fn) {
|
||||
// non-express app
|
||||
|
|
@ -235,8 +230,8 @@ app.use = function use(fn) {
|
|||
router.use(path, function mounted_app(req, res, next) {
|
||||
var orig = req.app;
|
||||
fn.handle(req, res, function (err) {
|
||||
setPrototypeOf(req, orig.request)
|
||||
setPrototypeOf(res, orig.response)
|
||||
Object.setPrototypeOf(req, orig.request)
|
||||
Object.setPrototypeOf(res, orig.response)
|
||||
next(err);
|
||||
});
|
||||
});
|
||||
|
|
@ -259,8 +254,7 @@ app.use = function use(fn) {
|
|||
*/
|
||||
|
||||
app.route = function route(path) {
|
||||
this.lazyrouter();
|
||||
return this._router.route(path);
|
||||
return this.router.route(path);
|
||||
};
|
||||
|
||||
/**
|
||||
|
|
@ -326,8 +320,6 @@ app.engine = function engine(ext, fn) {
|
|||
*/
|
||||
|
||||
app.param = function param(name, fn) {
|
||||
this.lazyrouter();
|
||||
|
||||
if (Array.isArray(name)) {
|
||||
for (var i = 0; i < name.length; i++) {
|
||||
this.param(name[i], fn);
|
||||
|
|
@ -336,7 +328,7 @@ app.param = function param(name, fn) {
|
|||
return this;
|
||||
}
|
||||
|
||||
this._router.param(name, fn);
|
||||
this.router.param(name, fn);
|
||||
|
||||
return this;
|
||||
};
|
||||
|
|
@ -359,17 +351,7 @@ app.param = function param(name, fn) {
|
|||
app.set = function set(setting, val) {
|
||||
if (arguments.length === 1) {
|
||||
// app.get(setting)
|
||||
var settings = this.settings
|
||||
|
||||
while (settings && settings !== Object.prototype) {
|
||||
if (hasOwnProperty.call(settings, setting)) {
|
||||
return settings[setting]
|
||||
}
|
||||
|
||||
settings = Object.getPrototypeOf(settings)
|
||||
}
|
||||
|
||||
return undefined
|
||||
return this.settings[setting];
|
||||
}
|
||||
|
||||
debug('set "%s" to %o', setting, val);
|
||||
|
|
@ -486,16 +468,14 @@ app.disable = function disable(setting) {
|
|||
* Delegate `.VERB(...)` calls to `router.VERB(...)`.
|
||||
*/
|
||||
|
||||
methods.forEach(function(method){
|
||||
app[method] = function(path){
|
||||
methods.forEach(function (method) {
|
||||
app[method] = function (path) {
|
||||
if (method === 'get' && arguments.length === 1) {
|
||||
// app.get(setting)
|
||||
return this.set(path);
|
||||
}
|
||||
|
||||
this.lazyrouter();
|
||||
|
||||
var route = this._router.route(path);
|
||||
var route = this.route(path);
|
||||
route[method].apply(route, slice.call(arguments, 1));
|
||||
return this;
|
||||
};
|
||||
|
|
@ -512,9 +492,7 @@ methods.forEach(function(method){
|
|||
*/
|
||||
|
||||
app.all = function all(path) {
|
||||
this.lazyrouter();
|
||||
|
||||
var route = this._router.route(path);
|
||||
var route = this.route(path);
|
||||
var args = slice.call(arguments, 1);
|
||||
|
||||
for (var i = 0; i < methods.length; i++) {
|
||||
|
|
@ -524,10 +502,6 @@ app.all = function all(path) {
|
|||
return this;
|
||||
};
|
||||
|
||||
// del -> delete alias
|
||||
|
||||
app.del = deprecate.function(app.delete, 'app.del: Use app.delete instead');
|
||||
|
||||
/**
|
||||
* Render the given view `name` name with `options`
|
||||
* and a callback accepting an error and the
|
||||
|
|
@ -550,7 +524,6 @@ app.render = function render(name, options, callback) {
|
|||
var done = callback;
|
||||
var engines = this.engines;
|
||||
var opts = options;
|
||||
var renderOptions = {};
|
||||
var view;
|
||||
|
||||
// support callback function as second arg
|
||||
|
|
@ -559,16 +532,8 @@ app.render = function render(name, options, callback) {
|
|||
opts = {};
|
||||
}
|
||||
|
||||
// merge app.locals
|
||||
merge(renderOptions, this.locals);
|
||||
|
||||
// merge options._locals
|
||||
if (opts._locals) {
|
||||
merge(renderOptions, opts._locals);
|
||||
}
|
||||
|
||||
// merge options
|
||||
merge(renderOptions, opts);
|
||||
var renderOptions = { ...this.locals, ...opts._locals, ...opts };
|
||||
|
||||
// set .cache unless explicitly provided
|
||||
if (renderOptions.cache == null) {
|
||||
|
|
@ -618,8 +583,8 @@ app.render = function render(name, options, callback) {
|
|||
* and HTTPS server you may do so with the "http"
|
||||
* and "https" modules as shown here:
|
||||
*
|
||||
* var http = require('http')
|
||||
* , https = require('https')
|
||||
* var http = require('node:http')
|
||||
* , https = require('node:https')
|
||||
* , express = require('express')
|
||||
* , app = express();
|
||||
*
|
||||
|
|
@ -631,9 +596,14 @@ app.render = function render(name, options, callback) {
|
|||
*/
|
||||
|
||||
app.listen = function listen() {
|
||||
var server = http.createServer(this);
|
||||
return server.listen.apply(server, arguments);
|
||||
};
|
||||
var server = http.createServer(this)
|
||||
var args = Array.prototype.slice.call(arguments)
|
||||
if (typeof args[args.length - 1] === 'function') {
|
||||
var done = args[args.length - 1] = once(args[args.length - 1])
|
||||
server.once('error', done)
|
||||
}
|
||||
return server.listen.apply(server, args)
|
||||
}
|
||||
|
||||
/**
|
||||
* Log error using console.error.
|
||||
|
|
|
|||
|
|
@ -13,11 +13,10 @@
|
|||
*/
|
||||
|
||||
var bodyParser = require('body-parser')
|
||||
var EventEmitter = require('events').EventEmitter;
|
||||
var EventEmitter = require('node:events').EventEmitter;
|
||||
var mixin = require('merge-descriptors');
|
||||
var proto = require('./application');
|
||||
var Route = require('./router/route');
|
||||
var Router = require('./router');
|
||||
var Router = require('router');
|
||||
var req = require('./request');
|
||||
var res = require('./response');
|
||||
|
||||
|
|
@ -68,7 +67,7 @@ exports.response = res;
|
|||
* Expose constructors.
|
||||
*/
|
||||
|
||||
exports.Route = Route;
|
||||
exports.Route = Router.Route;
|
||||
exports.Router = Router;
|
||||
|
||||
/**
|
||||
|
|
@ -76,41 +75,7 @@ exports.Router = Router;
|
|||
*/
|
||||
|
||||
exports.json = bodyParser.json
|
||||
exports.query = require('./middleware/query');
|
||||
exports.raw = bodyParser.raw
|
||||
exports.static = require('serve-static');
|
||||
exports.text = bodyParser.text
|
||||
exports.urlencoded = bodyParser.urlencoded
|
||||
|
||||
/**
|
||||
* Replace removed middleware with an appropriate error message.
|
||||
*/
|
||||
|
||||
var removedMiddlewares = [
|
||||
'bodyParser',
|
||||
'compress',
|
||||
'cookieSession',
|
||||
'session',
|
||||
'logger',
|
||||
'cookieParser',
|
||||
'favicon',
|
||||
'responseTime',
|
||||
'errorHandler',
|
||||
'timeout',
|
||||
'methodOverride',
|
||||
'vhost',
|
||||
'csrf',
|
||||
'directory',
|
||||
'limit',
|
||||
'multipart',
|
||||
'staticCache'
|
||||
]
|
||||
|
||||
removedMiddlewares.forEach(function (name) {
|
||||
Object.defineProperty(exports, name, {
|
||||
get: function () {
|
||||
throw new Error('Most middleware (like ' + name + ') is no longer bundled with Express and must be installed separately. Please see https://github.com/senchalabs/connect#middleware.');
|
||||
},
|
||||
configurable: true
|
||||
});
|
||||
});
|
||||
|
|
|
|||
|
|
@ -1,43 +0,0 @@
|
|||
/*!
|
||||
* express
|
||||
* Copyright(c) 2009-2013 TJ Holowaychuk
|
||||
* Copyright(c) 2013 Roman Shtylman
|
||||
* Copyright(c) 2014-2015 Douglas Christopher Wilson
|
||||
* MIT Licensed
|
||||
*/
|
||||
|
||||
'use strict';
|
||||
|
||||
/**
|
||||
* Module dependencies.
|
||||
* @private
|
||||
*/
|
||||
|
||||
var setPrototypeOf = require('setprototypeof')
|
||||
|
||||
/**
|
||||
* Initialization middleware, exposing the
|
||||
* request and response to each other, as well
|
||||
* as defaulting the X-Powered-By header field.
|
||||
*
|
||||
* @param {Function} app
|
||||
* @return {Function}
|
||||
* @api private
|
||||
*/
|
||||
|
||||
exports.init = function(app){
|
||||
return function expressInit(req, res, next){
|
||||
if (app.enabled('x-powered-by')) res.setHeader('X-Powered-By', 'Express');
|
||||
req.res = res;
|
||||
res.req = req;
|
||||
req.next = next;
|
||||
|
||||
setPrototypeOf(req, app.request)
|
||||
setPrototypeOf(res, app.response)
|
||||
|
||||
res.locals = res.locals || Object.create(null);
|
||||
|
||||
next();
|
||||
};
|
||||
};
|
||||
|
||||
|
|
@ -1,47 +0,0 @@
|
|||
/*!
|
||||
* express
|
||||
* Copyright(c) 2009-2013 TJ Holowaychuk
|
||||
* Copyright(c) 2013 Roman Shtylman
|
||||
* Copyright(c) 2014-2015 Douglas Christopher Wilson
|
||||
* MIT Licensed
|
||||
*/
|
||||
|
||||
'use strict';
|
||||
|
||||
/**
|
||||
* Module dependencies.
|
||||
*/
|
||||
|
||||
var merge = require('utils-merge')
|
||||
var parseUrl = require('parseurl');
|
||||
var qs = require('qs');
|
||||
|
||||
/**
|
||||
* @param {Object} options
|
||||
* @return {Function}
|
||||
* @api public
|
||||
*/
|
||||
|
||||
module.exports = function query(options) {
|
||||
var opts = merge({}, options)
|
||||
var queryparse = qs.parse;
|
||||
|
||||
if (typeof options === 'function') {
|
||||
queryparse = options;
|
||||
opts = undefined;
|
||||
}
|
||||
|
||||
if (opts !== undefined && opts.allowPrototypes === undefined) {
|
||||
// back-compat for qs module
|
||||
opts.allowPrototypes = true;
|
||||
}
|
||||
|
||||
return function query(req, res, next){
|
||||
if (!req.query) {
|
||||
var val = parseUrl(req).query;
|
||||
req.query = queryparse(val, opts);
|
||||
}
|
||||
|
||||
next();
|
||||
};
|
||||
};
|
||||
|
|
@ -14,10 +14,9 @@
|
|||
*/
|
||||
|
||||
var accepts = require('accepts');
|
||||
var deprecate = require('depd')('express');
|
||||
var isIP = require('net').isIP;
|
||||
var isIP = require('node:net').isIP;
|
||||
var typeis = require('type-is');
|
||||
var http = require('http');
|
||||
var http = require('node:http');
|
||||
var fresh = require('fresh');
|
||||
var parseRange = require('range-parser');
|
||||
var parse = require('parseurl');
|
||||
|
|
@ -147,9 +146,6 @@ req.acceptsEncodings = function(){
|
|||
return accept.encodings.apply(accept, arguments);
|
||||
};
|
||||
|
||||
req.acceptsEncoding = deprecate.function(req.acceptsEncodings,
|
||||
'req.acceptsEncoding: Use acceptsEncodings instead');
|
||||
|
||||
/**
|
||||
* Check if the given `charset`s are acceptable,
|
||||
* otherwise you should respond with 406 "Not Acceptable".
|
||||
|
|
@ -164,9 +160,6 @@ req.acceptsCharsets = function(){
|
|||
return accept.charsets.apply(accept, arguments);
|
||||
};
|
||||
|
||||
req.acceptsCharset = deprecate.function(req.acceptsCharsets,
|
||||
'req.acceptsCharset: Use acceptsCharsets instead');
|
||||
|
||||
/**
|
||||
* Check if the given `lang`s are acceptable,
|
||||
* otherwise you should respond with 406 "Not Acceptable".
|
||||
|
|
@ -181,9 +174,6 @@ req.acceptsLanguages = function(){
|
|||
return accept.languages.apply(accept, arguments);
|
||||
};
|
||||
|
||||
req.acceptsLanguage = deprecate.function(req.acceptsLanguages,
|
||||
'req.acceptsLanguage: Use acceptsLanguages instead');
|
||||
|
||||
/**
|
||||
* Parse Range header field, capping to the given `size`.
|
||||
*
|
||||
|
|
@ -216,38 +206,27 @@ req.range = function range(size, options) {
|
|||
};
|
||||
|
||||
/**
|
||||
* Return the value of param `name` when present or `defaultValue`.
|
||||
* Parse the query string of `req.url`.
|
||||
*
|
||||
* - Checks route placeholders, ex: _/user/:id_
|
||||
* - Checks body params, ex: id=12, {"id":12}
|
||||
* - Checks query string params, ex: ?id=12
|
||||
* This uses the "query parser" setting to parse the raw
|
||||
* string into an object.
|
||||
*
|
||||
* To utilize request bodies, `req.body`
|
||||
* should be an object. This can be done by using
|
||||
* the `bodyParser()` middleware.
|
||||
*
|
||||
* @param {String} name
|
||||
* @param {Mixed} [defaultValue]
|
||||
* @return {String}
|
||||
* @public
|
||||
* @api public
|
||||
*/
|
||||
|
||||
req.param = function param(name, defaultValue) {
|
||||
var params = this.params || {};
|
||||
var body = this.body || {};
|
||||
var query = this.query || {};
|
||||
defineGetter(req, 'query', function query(){
|
||||
var queryparse = this.app.get('query parser fn');
|
||||
|
||||
var args = arguments.length === 1
|
||||
? 'name'
|
||||
: 'name, default';
|
||||
deprecate('req.param(' + args + '): Use req.params, req.body, or req.query instead');
|
||||
if (!queryparse) {
|
||||
// parsing is disabled
|
||||
return Object.create(null);
|
||||
}
|
||||
|
||||
if (null != params[name] && params.hasOwnProperty(name)) return params[name];
|
||||
if (null != body[name]) return body[name];
|
||||
if (null != query[name]) return query[name];
|
||||
var querystring = parse(this).query;
|
||||
|
||||
return defaultValue;
|
||||
};
|
||||
return queryparse(querystring);
|
||||
});
|
||||
|
||||
/**
|
||||
* Check if the incoming request contains the "Content-Type"
|
||||
|
|
@ -414,7 +393,7 @@ defineGetter(req, 'path', function path() {
|
|||
});
|
||||
|
||||
/**
|
||||
* Parse the "Host" header field to a hostname.
|
||||
* Parse the "Host" header field to a host.
|
||||
*
|
||||
* When the "trust proxy" setting trusts the socket
|
||||
* address, the "X-Forwarded-Host" header field will
|
||||
|
|
@ -424,18 +403,35 @@ defineGetter(req, 'path', function path() {
|
|||
* @public
|
||||
*/
|
||||
|
||||
defineGetter(req, 'hostname', function hostname(){
|
||||
defineGetter(req, 'host', function host(){
|
||||
var trust = this.app.get('trust proxy fn');
|
||||
var host = this.get('X-Forwarded-Host');
|
||||
var val = this.get('X-Forwarded-Host');
|
||||
|
||||
if (!host || !trust(this.connection.remoteAddress, 0)) {
|
||||
host = this.get('Host');
|
||||
} else if (host.indexOf(',') !== -1) {
|
||||
if (!val || !trust(this.connection.remoteAddress, 0)) {
|
||||
val = this.get('Host');
|
||||
} else if (val.indexOf(',') !== -1) {
|
||||
// Note: X-Forwarded-Host is normally only ever a
|
||||
// single value, but this is to be safe.
|
||||
host = host.substring(0, host.indexOf(',')).trimRight()
|
||||
val = val.substring(0, val.indexOf(',')).trimRight()
|
||||
}
|
||||
|
||||
return val || undefined;
|
||||
});
|
||||
|
||||
/**
|
||||
* Parse the "Host" header field to a hostname.
|
||||
*
|
||||
* When the "trust proxy" setting trusts the socket
|
||||
* address, the "X-Forwarded-Host" header field will
|
||||
* be trusted.
|
||||
*
|
||||
* @return {String}
|
||||
* @api public
|
||||
*/
|
||||
|
||||
defineGetter(req, 'hostname', function hostname(){
|
||||
var host = this.host;
|
||||
|
||||
if (!host) return;
|
||||
|
||||
// IPv6 literal support
|
||||
|
|
@ -449,15 +445,9 @@ defineGetter(req, 'hostname', function hostname(){
|
|||
: host;
|
||||
});
|
||||
|
||||
// TODO: change req.host to return host in next major
|
||||
|
||||
defineGetter(req, 'host', deprecate.function(function host(){
|
||||
return this.hostname;
|
||||
}, 'req.host: Use req.hostname instead'));
|
||||
|
||||
/**
|
||||
* Check if the request is fresh, aka
|
||||
* Last-Modified and/or the ETag
|
||||
* Last-Modified or the ETag
|
||||
* still match.
|
||||
*
|
||||
* @return {Boolean}
|
||||
|
|
|
|||
263
lib/response.js
263
lib/response.js
|
|
@ -12,18 +12,16 @@
|
|||
* @private
|
||||
*/
|
||||
|
||||
var Buffer = require('safe-buffer').Buffer
|
||||
var contentDisposition = require('content-disposition');
|
||||
var createError = require('http-errors')
|
||||
var deprecate = require('depd')('express');
|
||||
var encodeUrl = require('encodeurl');
|
||||
var escapeHtml = require('escape-html');
|
||||
var http = require('http');
|
||||
var isAbsolute = require('./utils').isAbsolute;
|
||||
var http = require('node:http');
|
||||
var onFinished = require('on-finished');
|
||||
var path = require('path');
|
||||
var mime = require('mime-types')
|
||||
var path = require('node:path');
|
||||
var pathIsAbsolute = require('node:path').isAbsolute;
|
||||
var statuses = require('statuses')
|
||||
var merge = require('utils-merge');
|
||||
var sign = require('cookie-signature').sign;
|
||||
var normalizeType = require('./utils').normalizeType;
|
||||
var normalizeTypes = require('./utils').normalizeTypes;
|
||||
|
|
@ -31,7 +29,6 @@ var setCharset = require('./utils').setCharset;
|
|||
var cookie = require('cookie');
|
||||
var send = require('send');
|
||||
var extname = path.extname;
|
||||
var mime = send.mime;
|
||||
var resolve = path.resolve;
|
||||
var vary = require('vary');
|
||||
|
||||
|
|
@ -50,24 +47,28 @@ var res = Object.create(http.ServerResponse.prototype)
|
|||
module.exports = res
|
||||
|
||||
/**
|
||||
* Module variables.
|
||||
* @private
|
||||
*/
|
||||
|
||||
var charsetRegExp = /;\s*charset\s*=/;
|
||||
|
||||
/**
|
||||
* Set status `code`.
|
||||
* Set the HTTP status code for the response.
|
||||
*
|
||||
* @param {Number} code
|
||||
* @return {ServerResponse}
|
||||
* Expects an integer value between 100 and 999 inclusive.
|
||||
* Throws an error if the provided status code is not an integer or if it's outside the allowable range.
|
||||
*
|
||||
* @param {number} code - The HTTP status code to set.
|
||||
* @return {ServerResponse} - Returns itself for chaining methods.
|
||||
* @throws {TypeError} If `code` is not an integer.
|
||||
* @throws {RangeError} If `code` is outside the range 100 to 999.
|
||||
* @public
|
||||
*/
|
||||
|
||||
res.status = function status(code) {
|
||||
if ((typeof code === 'string' || Math.floor(code) !== code) && code > 99 && code < 1000) {
|
||||
deprecate('res.status(' + JSON.stringify(code) + '): use res.status(' + Math.floor(code) + ') instead')
|
||||
// Check if the status code is not an integer
|
||||
if (!Number.isInteger(code)) {
|
||||
throw new TypeError(`Invalid status code: ${JSON.stringify(code)}. Status code must be an integer.`);
|
||||
}
|
||||
// Check if the status code is outside of Node's valid range
|
||||
if (code < 100 || code > 999) {
|
||||
throw new RangeError(`Invalid status code: ${JSON.stringify(code)}. Status code must be greater than 99 and less than 1000.`);
|
||||
}
|
||||
|
||||
this.statusCode = code;
|
||||
return this;
|
||||
};
|
||||
|
|
@ -79,7 +80,11 @@ res.status = function status(code) {
|
|||
*
|
||||
* res.links({
|
||||
* next: 'http://api.example.com/users?page=2',
|
||||
* last: 'http://api.example.com/users?page=5'
|
||||
* last: 'http://api.example.com/users?page=5',
|
||||
* pages: [
|
||||
* 'http://api.example.com/users?page=1',
|
||||
* 'http://api.example.com/users?page=2'
|
||||
* ]
|
||||
* });
|
||||
*
|
||||
* @param {Object} links
|
||||
|
|
@ -87,11 +92,18 @@ res.status = function status(code) {
|
|||
* @public
|
||||
*/
|
||||
|
||||
res.links = function(links){
|
||||
res.links = function(links) {
|
||||
var link = this.get('Link') || '';
|
||||
if (link) link += ', ';
|
||||
return this.set('Link', link + Object.keys(links).map(function(rel){
|
||||
return '<' + links[rel] + '>; rel="' + rel + '"';
|
||||
return this.set('Link', link + Object.keys(links).map(function(rel) {
|
||||
// Allow multiple links if links[rel] is an array
|
||||
if (Array.isArray(links[rel])) {
|
||||
return links[rel].map(function (singleLink) {
|
||||
return `<${singleLink}>; rel="${rel}"`;
|
||||
}).join(', ');
|
||||
} else {
|
||||
return `<${links[rel]}>; rel="${rel}"`;
|
||||
}
|
||||
}).join(', '));
|
||||
};
|
||||
|
||||
|
|
@ -117,31 +129,6 @@ res.send = function send(body) {
|
|||
// settings
|
||||
var app = this.app;
|
||||
|
||||
// allow status / body
|
||||
if (arguments.length === 2) {
|
||||
// res.send(body, status) backwards compat
|
||||
if (typeof arguments[0] !== 'number' && typeof arguments[1] === 'number') {
|
||||
deprecate('res.send(body, status): Use res.status(status).send(body) instead');
|
||||
this.statusCode = arguments[1];
|
||||
} else {
|
||||
deprecate('res.send(status, body): Use res.status(status).send(body) instead');
|
||||
this.statusCode = arguments[0];
|
||||
chunk = arguments[1];
|
||||
}
|
||||
}
|
||||
|
||||
// disambiguate res.send(status) and res.send(status, num)
|
||||
if (typeof chunk === 'number' && arguments.length === 1) {
|
||||
// res.send(status) will set status message as text string
|
||||
if (!this.get('Content-Type')) {
|
||||
this.type('txt');
|
||||
}
|
||||
|
||||
deprecate('res.send(status): Use res.sendStatus(status) instead');
|
||||
this.statusCode = chunk;
|
||||
chunk = statuses.message[chunk]
|
||||
}
|
||||
|
||||
switch (typeof chunk) {
|
||||
// string defaulting to html
|
||||
case 'string':
|
||||
|
|
@ -154,7 +141,7 @@ res.send = function send(body) {
|
|||
case 'object':
|
||||
if (chunk === null) {
|
||||
chunk = '';
|
||||
} else if (Buffer.isBuffer(chunk)) {
|
||||
} else if (ArrayBuffer.isView(chunk)) {
|
||||
if (!this.get('Content-Type')) {
|
||||
this.type('bin');
|
||||
}
|
||||
|
|
@ -207,7 +194,7 @@ res.send = function send(body) {
|
|||
}
|
||||
|
||||
// freshness
|
||||
if (req.fresh) this.statusCode = 304;
|
||||
if (req.fresh) this.status(304);
|
||||
|
||||
// strip irrelevant headers
|
||||
if (204 === this.statusCode || 304 === this.statusCode) {
|
||||
|
|
@ -248,27 +235,12 @@ res.send = function send(body) {
|
|||
*/
|
||||
|
||||
res.json = function json(obj) {
|
||||
var val = obj;
|
||||
|
||||
// allow status / body
|
||||
if (arguments.length === 2) {
|
||||
// res.json(body, status) backwards compat
|
||||
if (typeof arguments[1] === 'number') {
|
||||
deprecate('res.json(obj, status): Use res.status(status).json(obj) instead');
|
||||
this.statusCode = arguments[1];
|
||||
} else {
|
||||
deprecate('res.json(status, obj): Use res.status(status).json(obj) instead');
|
||||
this.statusCode = arguments[0];
|
||||
val = arguments[1];
|
||||
}
|
||||
}
|
||||
|
||||
// settings
|
||||
var app = this.app;
|
||||
var escape = app.get('json escape')
|
||||
var replacer = app.get('json replacer');
|
||||
var spaces = app.get('json spaces');
|
||||
var body = stringify(val, replacer, spaces, escape)
|
||||
var body = stringify(obj, replacer, spaces, escape)
|
||||
|
||||
// content-type
|
||||
if (!this.get('Content-Type')) {
|
||||
|
|
@ -291,27 +263,12 @@ res.json = function json(obj) {
|
|||
*/
|
||||
|
||||
res.jsonp = function jsonp(obj) {
|
||||
var val = obj;
|
||||
|
||||
// allow status / body
|
||||
if (arguments.length === 2) {
|
||||
// res.jsonp(body, status) backwards compat
|
||||
if (typeof arguments[1] === 'number') {
|
||||
deprecate('res.jsonp(obj, status): Use res.status(status).jsonp(obj) instead');
|
||||
this.statusCode = arguments[1];
|
||||
} else {
|
||||
deprecate('res.jsonp(status, obj): Use res.status(status).jsonp(obj) instead');
|
||||
this.statusCode = arguments[0];
|
||||
val = arguments[1];
|
||||
}
|
||||
}
|
||||
|
||||
// settings
|
||||
var app = this.app;
|
||||
var escape = app.get('json escape')
|
||||
var replacer = app.get('json replacer');
|
||||
var spaces = app.get('json spaces');
|
||||
var body = stringify(val, replacer, spaces, escape)
|
||||
var body = stringify(obj, replacer, spaces, escape)
|
||||
var callback = this.req.query[app.get('jsonp callback name')];
|
||||
|
||||
// content-type
|
||||
|
|
@ -369,7 +326,7 @@ res.jsonp = function jsonp(obj) {
|
|||
res.sendStatus = function sendStatus(statusCode) {
|
||||
var body = statuses.message[statusCode] || String(statusCode)
|
||||
|
||||
this.statusCode = statusCode;
|
||||
this.status(statusCode);
|
||||
this.type('txt');
|
||||
|
||||
return this.send(body);
|
||||
|
|
@ -437,12 +394,15 @@ res.sendFile = function sendFile(path, options, callback) {
|
|||
opts = {};
|
||||
}
|
||||
|
||||
if (!opts.root && !isAbsolute(path)) {
|
||||
if (!opts.root && !pathIsAbsolute(path)) {
|
||||
throw new TypeError('path must be absolute or specify root to res.sendFile');
|
||||
}
|
||||
|
||||
// create file stream
|
||||
var pathname = encodeURI(path);
|
||||
|
||||
// wire application etag option to send
|
||||
opts.etag = this.app.enabled('etag');
|
||||
var file = send(req, pathname, opts);
|
||||
|
||||
// transfer
|
||||
|
|
@ -457,78 +417,6 @@ res.sendFile = function sendFile(path, options, callback) {
|
|||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* Transfer the file at the given `path`.
|
||||
*
|
||||
* Automatically sets the _Content-Type_ response header field.
|
||||
* The callback `callback(err)` is invoked when the transfer is complete
|
||||
* or when an error occurs. Be sure to check `res.headersSent`
|
||||
* if you wish to attempt responding, as the header and some data
|
||||
* may have already been transferred.
|
||||
*
|
||||
* Options:
|
||||
*
|
||||
* - `maxAge` defaulting to 0 (can be string converted by `ms`)
|
||||
* - `root` root directory for relative filenames
|
||||
* - `headers` object of headers to serve with file
|
||||
* - `dotfiles` serve dotfiles, defaulting to false; can be `"allow"` to send them
|
||||
*
|
||||
* Other options are passed along to `send`.
|
||||
*
|
||||
* Examples:
|
||||
*
|
||||
* The following example illustrates how `res.sendfile()` may
|
||||
* be used as an alternative for the `static()` middleware for
|
||||
* dynamic situations. The code backing `res.sendfile()` is actually
|
||||
* the same code, so HTTP cache support etc is identical.
|
||||
*
|
||||
* app.get('/user/:uid/photos/:file', function(req, res){
|
||||
* var uid = req.params.uid
|
||||
* , file = req.params.file;
|
||||
*
|
||||
* req.user.mayViewFilesFrom(uid, function(yes){
|
||||
* if (yes) {
|
||||
* res.sendfile('/uploads/' + uid + '/' + file);
|
||||
* } else {
|
||||
* res.send(403, 'Sorry! you cant see that.');
|
||||
* }
|
||||
* });
|
||||
* });
|
||||
*
|
||||
* @public
|
||||
*/
|
||||
|
||||
res.sendfile = function (path, options, callback) {
|
||||
var done = callback;
|
||||
var req = this.req;
|
||||
var res = this;
|
||||
var next = req.next;
|
||||
var opts = options || {};
|
||||
|
||||
// support function as second arg
|
||||
if (typeof options === 'function') {
|
||||
done = options;
|
||||
opts = {};
|
||||
}
|
||||
|
||||
// create file stream
|
||||
var file = send(req, path, opts);
|
||||
|
||||
// transfer
|
||||
sendfile(res, file, opts, function (err) {
|
||||
if (done) return done(err);
|
||||
if (err && err.code === 'EISDIR') return next();
|
||||
|
||||
// next() all but write errors
|
||||
if (err && err.code !== 'ECONNABORTED' && err.syscall !== 'write') {
|
||||
next(err);
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
res.sendfile = deprecate.function(res.sendfile,
|
||||
'res.sendfile: Use res.sendFile instead');
|
||||
|
||||
/**
|
||||
* Transfer the file at the given `path` as an attachment.
|
||||
*
|
||||
|
|
@ -599,8 +487,10 @@ res.download = function download (path, filename, options, callback) {
|
|||
};
|
||||
|
||||
/**
|
||||
* Set _Content-Type_ response header with `type` through `mime.lookup()`
|
||||
* Set _Content-Type_ response header with `type` through `mime.contentType()`
|
||||
* when it does not contain "/", or set the Content-Type to `type` otherwise.
|
||||
* When no mapping is found though `mime.contentType()`, the type is set to
|
||||
* "application/octet-stream".
|
||||
*
|
||||
* Examples:
|
||||
*
|
||||
|
|
@ -618,7 +508,7 @@ res.download = function download (path, filename, options, callback) {
|
|||
res.contentType =
|
||||
res.type = function contentType(type) {
|
||||
var ct = type.indexOf('/') === -1
|
||||
? mime.lookup(type)
|
||||
? (mime.contentType(type) || 'application/octet-stream')
|
||||
: type;
|
||||
|
||||
return this.set('Content-Type', ct);
|
||||
|
|
@ -767,6 +657,9 @@ res.append = function append(field, val) {
|
|||
*
|
||||
* Aliased as `res.header()`.
|
||||
*
|
||||
* When the set header is "Content-Type", the type is expanded to include
|
||||
* the charset if not present using `mime.contentType()`.
|
||||
*
|
||||
* @param {String|Object} field
|
||||
* @param {String|Array} val
|
||||
* @return {ServerResponse} for chaining
|
||||
|
|
@ -785,10 +678,7 @@ res.header = function header(field, val) {
|
|||
if (Array.isArray(value)) {
|
||||
throw new TypeError('Content-Type cannot be set to an Array');
|
||||
}
|
||||
if (!charsetRegExp.test(value)) {
|
||||
var charset = mime.charsets.lookup(value.split(';')[0]);
|
||||
if (charset) value += '; charset=' + charset.toLowerCase();
|
||||
}
|
||||
value = mime.contentType(value)
|
||||
}
|
||||
|
||||
this.setHeader(field, value);
|
||||
|
|
@ -822,15 +712,10 @@ res.get = function(field){
|
|||
*/
|
||||
|
||||
res.clearCookie = function clearCookie(name, options) {
|
||||
if (options) {
|
||||
if (options.maxAge) {
|
||||
deprecate('res.clearCookie: Passing "options.maxAge" is deprecated. In v5.0.0 of Express, this option will be ignored, as res.clearCookie will automatically set cookies to expire immediately. Please update your code to omit this option.');
|
||||
}
|
||||
if (options.expires) {
|
||||
deprecate('res.clearCookie: Passing "options.expires" is deprecated. In v5.0.0 of Express, this option will be ignored, as res.clearCookie will automatically set cookies to expire immediately. Please update your code to omit this option.');
|
||||
}
|
||||
}
|
||||
var opts = merge({ expires: new Date(1), path: '/' }, options);
|
||||
// Force cookie expiration by setting expires to the past
|
||||
const opts = { path: '/', ...options, expires: new Date(1)};
|
||||
// ensure maxAge is not passed
|
||||
delete opts.maxAge
|
||||
|
||||
return this.cookie(name, '', opts);
|
||||
};
|
||||
|
|
@ -860,7 +745,7 @@ res.clearCookie = function clearCookie(name, options) {
|
|||
*/
|
||||
|
||||
res.cookie = function (name, value, options) {
|
||||
var opts = merge({}, options);
|
||||
var opts = { ...options };
|
||||
var secret = this.req.secret;
|
||||
var signed = opts.signed;
|
||||
|
||||
|
|
@ -912,26 +797,13 @@ res.cookie = function (name, value, options) {
|
|||
*/
|
||||
|
||||
res.location = function location(url) {
|
||||
var loc;
|
||||
|
||||
// "back" is an alias for the referrer
|
||||
if (url === 'back') {
|
||||
loc = this.req.get('Referrer') || '/';
|
||||
} else {
|
||||
loc = String(url);
|
||||
}
|
||||
|
||||
return this.set('Location', encodeUrl(loc));
|
||||
return this.set('Location', encodeUrl(url));
|
||||
};
|
||||
|
||||
/**
|
||||
* Redirect to the given `url` with optional response `status`
|
||||
* defaulting to 302.
|
||||
*
|
||||
* The resulting `url` is determined by `res.location()`, so
|
||||
* it will play nicely with mounted apps, relative paths,
|
||||
* `"back"` etc.
|
||||
*
|
||||
* Examples:
|
||||
*
|
||||
* res.redirect('/foo/bar');
|
||||
|
|
@ -949,13 +821,8 @@ res.redirect = function redirect(url) {
|
|||
|
||||
// allow status / url
|
||||
if (arguments.length === 2) {
|
||||
if (typeof arguments[0] === 'number') {
|
||||
status = arguments[0];
|
||||
address = arguments[1];
|
||||
} else {
|
||||
deprecate('res.redirect(url, status): Use res.redirect(status, url) instead');
|
||||
status = arguments[1];
|
||||
}
|
||||
status = arguments[0]
|
||||
address = arguments[1]
|
||||
}
|
||||
|
||||
// Set location header
|
||||
|
|
@ -969,7 +836,7 @@ res.redirect = function redirect(url) {
|
|||
|
||||
html: function(){
|
||||
var u = escapeHtml(address);
|
||||
body = '<p>' + statuses.message[status] + '. Redirecting to <a href="' + u + '">' + u + '</a></p>'
|
||||
body = '<p>' + statuses.message[status] + '. Redirecting to ' + u + '</p>'
|
||||
},
|
||||
|
||||
default: function(){
|
||||
|
|
@ -978,7 +845,7 @@ res.redirect = function redirect(url) {
|
|||
});
|
||||
|
||||
// Respond
|
||||
this.statusCode = status;
|
||||
this.status(status);
|
||||
this.set('Content-Length', Buffer.byteLength(body));
|
||||
|
||||
if (this.req.method === 'HEAD') {
|
||||
|
|
@ -998,12 +865,6 @@ res.redirect = function redirect(url) {
|
|||
*/
|
||||
|
||||
res.vary = function(field){
|
||||
// checks for back-compat
|
||||
if (!field || (Array.isArray(field) && !field.length)) {
|
||||
deprecate('res.vary(): Provide a field name');
|
||||
return this;
|
||||
}
|
||||
|
||||
vary(this, field);
|
||||
|
||||
return this;
|
||||
|
|
|
|||
|
|
@ -1,673 +0,0 @@
|
|||
/*!
|
||||
* express
|
||||
* Copyright(c) 2009-2013 TJ Holowaychuk
|
||||
* Copyright(c) 2013 Roman Shtylman
|
||||
* Copyright(c) 2014-2015 Douglas Christopher Wilson
|
||||
* MIT Licensed
|
||||
*/
|
||||
|
||||
'use strict';
|
||||
|
||||
/**
|
||||
* Module dependencies.
|
||||
* @private
|
||||
*/
|
||||
|
||||
var Route = require('./route');
|
||||
var Layer = require('./layer');
|
||||
var methods = require('methods');
|
||||
var mixin = require('utils-merge');
|
||||
var debug = require('debug')('express:router');
|
||||
var deprecate = require('depd')('express');
|
||||
var flatten = require('array-flatten');
|
||||
var parseUrl = require('parseurl');
|
||||
var setPrototypeOf = require('setprototypeof')
|
||||
|
||||
/**
|
||||
* Module variables.
|
||||
* @private
|
||||
*/
|
||||
|
||||
var objectRegExp = /^\[object (\S+)\]$/;
|
||||
var slice = Array.prototype.slice;
|
||||
var toString = Object.prototype.toString;
|
||||
|
||||
/**
|
||||
* Initialize a new `Router` with the given `options`.
|
||||
*
|
||||
* @param {Object} [options]
|
||||
* @return {Router} which is a callable function
|
||||
* @public
|
||||
*/
|
||||
|
||||
var proto = module.exports = function(options) {
|
||||
var opts = options || {};
|
||||
|
||||
function router(req, res, next) {
|
||||
router.handle(req, res, next);
|
||||
}
|
||||
|
||||
// mixin Router class functions
|
||||
setPrototypeOf(router, proto)
|
||||
|
||||
router.params = {};
|
||||
router._params = [];
|
||||
router.caseSensitive = opts.caseSensitive;
|
||||
router.mergeParams = opts.mergeParams;
|
||||
router.strict = opts.strict;
|
||||
router.stack = [];
|
||||
|
||||
return router;
|
||||
};
|
||||
|
||||
/**
|
||||
* Map the given param placeholder `name`(s) to the given callback.
|
||||
*
|
||||
* Parameter mapping is used to provide pre-conditions to routes
|
||||
* which use normalized placeholders. For example a _:user_id_ parameter
|
||||
* could automatically load a user's information from the database without
|
||||
* any additional code,
|
||||
*
|
||||
* The callback uses the same signature as middleware, the only difference
|
||||
* being that the value of the placeholder is passed, in this case the _id_
|
||||
* of the user. Once the `next()` function is invoked, just like middleware
|
||||
* it will continue on to execute the route, or subsequent parameter functions.
|
||||
*
|
||||
* Just like in middleware, you must either respond to the request or call next
|
||||
* to avoid stalling the request.
|
||||
*
|
||||
* app.param('user_id', function(req, res, next, id){
|
||||
* User.find(id, function(err, user){
|
||||
* if (err) {
|
||||
* return next(err);
|
||||
* } else if (!user) {
|
||||
* return next(new Error('failed to load user'));
|
||||
* }
|
||||
* req.user = user;
|
||||
* next();
|
||||
* });
|
||||
* });
|
||||
*
|
||||
* @param {String} name
|
||||
* @param {Function} fn
|
||||
* @return {app} for chaining
|
||||
* @public
|
||||
*/
|
||||
|
||||
proto.param = function param(name, fn) {
|
||||
// param logic
|
||||
if (typeof name === 'function') {
|
||||
deprecate('router.param(fn): Refactor to use path params');
|
||||
this._params.push(name);
|
||||
return;
|
||||
}
|
||||
|
||||
// apply param functions
|
||||
var params = this._params;
|
||||
var len = params.length;
|
||||
var ret;
|
||||
|
||||
if (name[0] === ':') {
|
||||
deprecate('router.param(' + JSON.stringify(name) + ', fn): Use router.param(' + JSON.stringify(name.slice(1)) + ', fn) instead')
|
||||
name = name.slice(1)
|
||||
}
|
||||
|
||||
for (var i = 0; i < len; ++i) {
|
||||
if (ret = params[i](name, fn)) {
|
||||
fn = ret;
|
||||
}
|
||||
}
|
||||
|
||||
// ensure we end up with a
|
||||
// middleware function
|
||||
if ('function' !== typeof fn) {
|
||||
throw new Error('invalid param() call for ' + name + ', got ' + fn);
|
||||
}
|
||||
|
||||
(this.params[name] = this.params[name] || []).push(fn);
|
||||
return this;
|
||||
};
|
||||
|
||||
/**
|
||||
* Dispatch a req, res into the router.
|
||||
* @private
|
||||
*/
|
||||
|
||||
proto.handle = function handle(req, res, out) {
|
||||
var self = this;
|
||||
|
||||
debug('dispatching %s %s', req.method, req.url);
|
||||
|
||||
var idx = 0;
|
||||
var protohost = getProtohost(req.url) || ''
|
||||
var removed = '';
|
||||
var slashAdded = false;
|
||||
var sync = 0
|
||||
var paramcalled = {};
|
||||
|
||||
// store options for OPTIONS request
|
||||
// only used if OPTIONS request
|
||||
var options = [];
|
||||
|
||||
// middleware and routes
|
||||
var stack = self.stack;
|
||||
|
||||
// manage inter-router variables
|
||||
var parentParams = req.params;
|
||||
var parentUrl = req.baseUrl || '';
|
||||
var done = restore(out, req, 'baseUrl', 'next', 'params');
|
||||
|
||||
// setup next layer
|
||||
req.next = next;
|
||||
|
||||
// for options requests, respond with a default if nothing else responds
|
||||
if (req.method === 'OPTIONS') {
|
||||
done = wrap(done, function(old, err) {
|
||||
if (err || options.length === 0) return old(err);
|
||||
sendOptionsResponse(res, options, old);
|
||||
});
|
||||
}
|
||||
|
||||
// setup basic req values
|
||||
req.baseUrl = parentUrl;
|
||||
req.originalUrl = req.originalUrl || req.url;
|
||||
|
||||
next();
|
||||
|
||||
function next(err) {
|
||||
var layerError = err === 'route'
|
||||
? null
|
||||
: err;
|
||||
|
||||
// remove added slash
|
||||
if (slashAdded) {
|
||||
req.url = req.url.slice(1)
|
||||
slashAdded = false;
|
||||
}
|
||||
|
||||
// restore altered req.url
|
||||
if (removed.length !== 0) {
|
||||
req.baseUrl = parentUrl;
|
||||
req.url = protohost + removed + req.url.slice(protohost.length)
|
||||
removed = '';
|
||||
}
|
||||
|
||||
// signal to exit router
|
||||
if (layerError === 'router') {
|
||||
setImmediate(done, null)
|
||||
return
|
||||
}
|
||||
|
||||
// no more matching layers
|
||||
if (idx >= stack.length) {
|
||||
setImmediate(done, layerError);
|
||||
return;
|
||||
}
|
||||
|
||||
// max sync stack
|
||||
if (++sync > 100) {
|
||||
return setImmediate(next, err)
|
||||
}
|
||||
|
||||
// get pathname of request
|
||||
var path = getPathname(req);
|
||||
|
||||
if (path == null) {
|
||||
return done(layerError);
|
||||
}
|
||||
|
||||
// find next matching layer
|
||||
var layer;
|
||||
var match;
|
||||
var route;
|
||||
|
||||
while (match !== true && idx < stack.length) {
|
||||
layer = stack[idx++];
|
||||
match = matchLayer(layer, path);
|
||||
route = layer.route;
|
||||
|
||||
if (typeof match !== 'boolean') {
|
||||
// hold on to layerError
|
||||
layerError = layerError || match;
|
||||
}
|
||||
|
||||
if (match !== true) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!route) {
|
||||
// process non-route handlers normally
|
||||
continue;
|
||||
}
|
||||
|
||||
if (layerError) {
|
||||
// routes do not match with a pending error
|
||||
match = false;
|
||||
continue;
|
||||
}
|
||||
|
||||
var method = req.method;
|
||||
var has_method = route._handles_method(method);
|
||||
|
||||
// build up automatic options response
|
||||
if (!has_method && method === 'OPTIONS') {
|
||||
appendMethods(options, route._options());
|
||||
}
|
||||
|
||||
// don't even bother matching route
|
||||
if (!has_method && method !== 'HEAD') {
|
||||
match = false;
|
||||
}
|
||||
}
|
||||
|
||||
// no match
|
||||
if (match !== true) {
|
||||
return done(layerError);
|
||||
}
|
||||
|
||||
// store route for dispatch on change
|
||||
if (route) {
|
||||
req.route = route;
|
||||
}
|
||||
|
||||
// Capture one-time layer values
|
||||
req.params = self.mergeParams
|
||||
? mergeParams(layer.params, parentParams)
|
||||
: layer.params;
|
||||
var layerPath = layer.path;
|
||||
|
||||
// this should be done for the layer
|
||||
self.process_params(layer, paramcalled, req, res, function (err) {
|
||||
if (err) {
|
||||
next(layerError || err)
|
||||
} else if (route) {
|
||||
layer.handle_request(req, res, next)
|
||||
} else {
|
||||
trim_prefix(layer, layerError, layerPath, path)
|
||||
}
|
||||
|
||||
sync = 0
|
||||
});
|
||||
}
|
||||
|
||||
function trim_prefix(layer, layerError, layerPath, path) {
|
||||
if (layerPath.length !== 0) {
|
||||
// Validate path is a prefix match
|
||||
if (layerPath !== path.slice(0, layerPath.length)) {
|
||||
next(layerError)
|
||||
return
|
||||
}
|
||||
|
||||
// Validate path breaks on a path separator
|
||||
var c = path[layerPath.length]
|
||||
if (c && c !== '/' && c !== '.') return next(layerError)
|
||||
|
||||
// Trim off the part of the url that matches the route
|
||||
// middleware (.use stuff) needs to have the path stripped
|
||||
debug('trim prefix (%s) from url %s', layerPath, req.url);
|
||||
removed = layerPath;
|
||||
req.url = protohost + req.url.slice(protohost.length + removed.length)
|
||||
|
||||
// Ensure leading slash
|
||||
if (!protohost && req.url[0] !== '/') {
|
||||
req.url = '/' + req.url;
|
||||
slashAdded = true;
|
||||
}
|
||||
|
||||
// Setup base URL (no trailing slash)
|
||||
req.baseUrl = parentUrl + (removed[removed.length - 1] === '/'
|
||||
? removed.substring(0, removed.length - 1)
|
||||
: removed);
|
||||
}
|
||||
|
||||
debug('%s %s : %s', layer.name, layerPath, req.originalUrl);
|
||||
|
||||
if (layerError) {
|
||||
layer.handle_error(layerError, req, res, next);
|
||||
} else {
|
||||
layer.handle_request(req, res, next);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Process any parameters for the layer.
|
||||
* @private
|
||||
*/
|
||||
|
||||
proto.process_params = function process_params(layer, called, req, res, done) {
|
||||
var params = this.params;
|
||||
|
||||
// captured parameters from the layer, keys and values
|
||||
var keys = layer.keys;
|
||||
|
||||
// fast track
|
||||
if (!keys || keys.length === 0) {
|
||||
return done();
|
||||
}
|
||||
|
||||
var i = 0;
|
||||
var name;
|
||||
var paramIndex = 0;
|
||||
var key;
|
||||
var paramVal;
|
||||
var paramCallbacks;
|
||||
var paramCalled;
|
||||
|
||||
// process params in order
|
||||
// param callbacks can be async
|
||||
function param(err) {
|
||||
if (err) {
|
||||
return done(err);
|
||||
}
|
||||
|
||||
if (i >= keys.length ) {
|
||||
return done();
|
||||
}
|
||||
|
||||
paramIndex = 0;
|
||||
key = keys[i++];
|
||||
name = key.name;
|
||||
paramVal = req.params[name];
|
||||
paramCallbacks = params[name];
|
||||
paramCalled = called[name];
|
||||
|
||||
if (paramVal === undefined || !paramCallbacks) {
|
||||
return param();
|
||||
}
|
||||
|
||||
// param previously called with same value or error occurred
|
||||
if (paramCalled && (paramCalled.match === paramVal
|
||||
|| (paramCalled.error && paramCalled.error !== 'route'))) {
|
||||
// restore value
|
||||
req.params[name] = paramCalled.value;
|
||||
|
||||
// next param
|
||||
return param(paramCalled.error);
|
||||
}
|
||||
|
||||
called[name] = paramCalled = {
|
||||
error: null,
|
||||
match: paramVal,
|
||||
value: paramVal
|
||||
};
|
||||
|
||||
paramCallback();
|
||||
}
|
||||
|
||||
// single param callbacks
|
||||
function paramCallback(err) {
|
||||
var fn = paramCallbacks[paramIndex++];
|
||||
|
||||
// store updated value
|
||||
paramCalled.value = req.params[key.name];
|
||||
|
||||
if (err) {
|
||||
// store error
|
||||
paramCalled.error = err;
|
||||
param(err);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!fn) return param();
|
||||
|
||||
try {
|
||||
fn(req, res, paramCallback, paramVal, key.name);
|
||||
} catch (e) {
|
||||
paramCallback(e);
|
||||
}
|
||||
}
|
||||
|
||||
param();
|
||||
};
|
||||
|
||||
/**
|
||||
* Use the given middleware function, with optional path, defaulting to "/".
|
||||
*
|
||||
* Use (like `.all`) will run for any http METHOD, but it will not add
|
||||
* handlers for those methods so OPTIONS requests will not consider `.use`
|
||||
* functions even if they could respond.
|
||||
*
|
||||
* The other difference is that _route_ path is stripped and not visible
|
||||
* to the handler function. The main effect of this feature is that mounted
|
||||
* handlers can operate without any code changes regardless of the "prefix"
|
||||
* pathname.
|
||||
*
|
||||
* @public
|
||||
*/
|
||||
|
||||
proto.use = function use(fn) {
|
||||
var offset = 0;
|
||||
var path = '/';
|
||||
|
||||
// default path to '/'
|
||||
// disambiguate router.use([fn])
|
||||
if (typeof fn !== 'function') {
|
||||
var arg = fn;
|
||||
|
||||
while (Array.isArray(arg) && arg.length !== 0) {
|
||||
arg = arg[0];
|
||||
}
|
||||
|
||||
// first arg is the path
|
||||
if (typeof arg !== 'function') {
|
||||
offset = 1;
|
||||
path = fn;
|
||||
}
|
||||
}
|
||||
|
||||
var callbacks = flatten(slice.call(arguments, offset));
|
||||
|
||||
if (callbacks.length === 0) {
|
||||
throw new TypeError('Router.use() requires a middleware function')
|
||||
}
|
||||
|
||||
for (var i = 0; i < callbacks.length; i++) {
|
||||
var fn = callbacks[i];
|
||||
|
||||
if (typeof fn !== 'function') {
|
||||
throw new TypeError('Router.use() requires a middleware function but got a ' + gettype(fn))
|
||||
}
|
||||
|
||||
// add the middleware
|
||||
debug('use %o %s', path, fn.name || '<anonymous>')
|
||||
|
||||
var layer = new Layer(path, {
|
||||
sensitive: this.caseSensitive,
|
||||
strict: false,
|
||||
end: false
|
||||
}, fn);
|
||||
|
||||
layer.route = undefined;
|
||||
|
||||
this.stack.push(layer);
|
||||
}
|
||||
|
||||
return this;
|
||||
};
|
||||
|
||||
/**
|
||||
* Create a new Route for the given path.
|
||||
*
|
||||
* Each route contains a separate middleware stack and VERB handlers.
|
||||
*
|
||||
* See the Route api documentation for details on adding handlers
|
||||
* and middleware to routes.
|
||||
*
|
||||
* @param {String} path
|
||||
* @return {Route}
|
||||
* @public
|
||||
*/
|
||||
|
||||
proto.route = function route(path) {
|
||||
var route = new Route(path);
|
||||
|
||||
var layer = new Layer(path, {
|
||||
sensitive: this.caseSensitive,
|
||||
strict: this.strict,
|
||||
end: true
|
||||
}, route.dispatch.bind(route));
|
||||
|
||||
layer.route = route;
|
||||
|
||||
this.stack.push(layer);
|
||||
return route;
|
||||
};
|
||||
|
||||
// create Router#VERB functions
|
||||
methods.concat('all').forEach(function(method){
|
||||
proto[method] = function(path){
|
||||
var route = this.route(path)
|
||||
route[method].apply(route, slice.call(arguments, 1));
|
||||
return this;
|
||||
};
|
||||
});
|
||||
|
||||
// append methods to a list of methods
|
||||
function appendMethods(list, addition) {
|
||||
for (var i = 0; i < addition.length; i++) {
|
||||
var method = addition[i];
|
||||
if (list.indexOf(method) === -1) {
|
||||
list.push(method);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// get pathname of request
|
||||
function getPathname(req) {
|
||||
try {
|
||||
return parseUrl(req).pathname;
|
||||
} catch (err) {
|
||||
return undefined;
|
||||
}
|
||||
}
|
||||
|
||||
// Get get protocol + host for a URL
|
||||
function getProtohost(url) {
|
||||
if (typeof url !== 'string' || url.length === 0 || url[0] === '/') {
|
||||
return undefined
|
||||
}
|
||||
|
||||
var searchIndex = url.indexOf('?')
|
||||
var pathLength = searchIndex !== -1
|
||||
? searchIndex
|
||||
: url.length
|
||||
var fqdnIndex = url.slice(0, pathLength).indexOf('://')
|
||||
|
||||
return fqdnIndex !== -1
|
||||
? url.substring(0, url.indexOf('/', 3 + fqdnIndex))
|
||||
: undefined
|
||||
}
|
||||
|
||||
// get type for error message
|
||||
function gettype(obj) {
|
||||
var type = typeof obj;
|
||||
|
||||
if (type !== 'object') {
|
||||
return type;
|
||||
}
|
||||
|
||||
// inspect [[Class]] for objects
|
||||
return toString.call(obj)
|
||||
.replace(objectRegExp, '$1');
|
||||
}
|
||||
|
||||
/**
|
||||
* Match path to a layer.
|
||||
*
|
||||
* @param {Layer} layer
|
||||
* @param {string} path
|
||||
* @private
|
||||
*/
|
||||
|
||||
function matchLayer(layer, path) {
|
||||
try {
|
||||
return layer.match(path);
|
||||
} catch (err) {
|
||||
return err;
|
||||
}
|
||||
}
|
||||
|
||||
// merge params with parent params
|
||||
function mergeParams(params, parent) {
|
||||
if (typeof parent !== 'object' || !parent) {
|
||||
return params;
|
||||
}
|
||||
|
||||
// make copy of parent for base
|
||||
var obj = mixin({}, parent);
|
||||
|
||||
// simple non-numeric merging
|
||||
if (!(0 in params) || !(0 in parent)) {
|
||||
return mixin(obj, params);
|
||||
}
|
||||
|
||||
var i = 0;
|
||||
var o = 0;
|
||||
|
||||
// determine numeric gaps
|
||||
while (i in params) {
|
||||
i++;
|
||||
}
|
||||
|
||||
while (o in parent) {
|
||||
o++;
|
||||
}
|
||||
|
||||
// offset numeric indices in params before merge
|
||||
for (i--; i >= 0; i--) {
|
||||
params[i + o] = params[i];
|
||||
|
||||
// create holes for the merge when necessary
|
||||
if (i < o) {
|
||||
delete params[i];
|
||||
}
|
||||
}
|
||||
|
||||
return mixin(obj, params);
|
||||
}
|
||||
|
||||
// restore obj props after function
|
||||
function restore(fn, obj) {
|
||||
var props = new Array(arguments.length - 2);
|
||||
var vals = new Array(arguments.length - 2);
|
||||
|
||||
for (var i = 0; i < props.length; i++) {
|
||||
props[i] = arguments[i + 2];
|
||||
vals[i] = obj[props[i]];
|
||||
}
|
||||
|
||||
return function () {
|
||||
// restore vals
|
||||
for (var i = 0; i < props.length; i++) {
|
||||
obj[props[i]] = vals[i];
|
||||
}
|
||||
|
||||
return fn.apply(this, arguments);
|
||||
};
|
||||
}
|
||||
|
||||
// send an OPTIONS response
|
||||
function sendOptionsResponse(res, options, next) {
|
||||
try {
|
||||
var body = options.join(',');
|
||||
res.set('Allow', body);
|
||||
res.send(body);
|
||||
} catch (err) {
|
||||
next(err);
|
||||
}
|
||||
}
|
||||
|
||||
// wrap a function
|
||||
function wrap(old, fn) {
|
||||
return function proxy() {
|
||||
var args = new Array(arguments.length + 1);
|
||||
|
||||
args[0] = old;
|
||||
for (var i = 0, len = arguments.length; i < len; i++) {
|
||||
args[i + 1] = arguments[i];
|
||||
}
|
||||
|
||||
fn.apply(this, args);
|
||||
};
|
||||
}
|
||||
|
|
@ -1,181 +0,0 @@
|
|||
/*!
|
||||
* express
|
||||
* Copyright(c) 2009-2013 TJ Holowaychuk
|
||||
* Copyright(c) 2013 Roman Shtylman
|
||||
* Copyright(c) 2014-2015 Douglas Christopher Wilson
|
||||
* MIT Licensed
|
||||
*/
|
||||
|
||||
'use strict';
|
||||
|
||||
/**
|
||||
* Module dependencies.
|
||||
* @private
|
||||
*/
|
||||
|
||||
var pathRegexp = require('path-to-regexp');
|
||||
var debug = require('debug')('express:router:layer');
|
||||
|
||||
/**
|
||||
* Module variables.
|
||||
* @private
|
||||
*/
|
||||
|
||||
var hasOwnProperty = Object.prototype.hasOwnProperty;
|
||||
|
||||
/**
|
||||
* Module exports.
|
||||
* @public
|
||||
*/
|
||||
|
||||
module.exports = Layer;
|
||||
|
||||
function Layer(path, options, fn) {
|
||||
if (!(this instanceof Layer)) {
|
||||
return new Layer(path, options, fn);
|
||||
}
|
||||
|
||||
debug('new %o', path)
|
||||
var opts = options || {};
|
||||
|
||||
this.handle = fn;
|
||||
this.name = fn.name || '<anonymous>';
|
||||
this.params = undefined;
|
||||
this.path = undefined;
|
||||
this.regexp = pathRegexp(path, this.keys = [], opts);
|
||||
|
||||
// set fast path flags
|
||||
this.regexp.fast_star = path === '*'
|
||||
this.regexp.fast_slash = path === '/' && opts.end === false
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle the error for the layer.
|
||||
*
|
||||
* @param {Error} error
|
||||
* @param {Request} req
|
||||
* @param {Response} res
|
||||
* @param {function} next
|
||||
* @api private
|
||||
*/
|
||||
|
||||
Layer.prototype.handle_error = function handle_error(error, req, res, next) {
|
||||
var fn = this.handle;
|
||||
|
||||
if (fn.length !== 4) {
|
||||
// not a standard error handler
|
||||
return next(error);
|
||||
}
|
||||
|
||||
try {
|
||||
fn(error, req, res, next);
|
||||
} catch (err) {
|
||||
next(err);
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Handle the request for the layer.
|
||||
*
|
||||
* @param {Request} req
|
||||
* @param {Response} res
|
||||
* @param {function} next
|
||||
* @api private
|
||||
*/
|
||||
|
||||
Layer.prototype.handle_request = function handle(req, res, next) {
|
||||
var fn = this.handle;
|
||||
|
||||
if (fn.length > 3) {
|
||||
// not a standard request handler
|
||||
return next();
|
||||
}
|
||||
|
||||
try {
|
||||
fn(req, res, next);
|
||||
} catch (err) {
|
||||
next(err);
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Check if this route matches `path`, if so
|
||||
* populate `.params`.
|
||||
*
|
||||
* @param {String} path
|
||||
* @return {Boolean}
|
||||
* @api private
|
||||
*/
|
||||
|
||||
Layer.prototype.match = function match(path) {
|
||||
var match
|
||||
|
||||
if (path != null) {
|
||||
// fast path non-ending match for / (any path matches)
|
||||
if (this.regexp.fast_slash) {
|
||||
this.params = {}
|
||||
this.path = ''
|
||||
return true
|
||||
}
|
||||
|
||||
// fast path for * (everything matched in a param)
|
||||
if (this.regexp.fast_star) {
|
||||
this.params = {'0': decode_param(path)}
|
||||
this.path = path
|
||||
return true
|
||||
}
|
||||
|
||||
// match the path
|
||||
match = this.regexp.exec(path)
|
||||
}
|
||||
|
||||
if (!match) {
|
||||
this.params = undefined;
|
||||
this.path = undefined;
|
||||
return false;
|
||||
}
|
||||
|
||||
// store values
|
||||
this.params = {};
|
||||
this.path = match[0]
|
||||
|
||||
var keys = this.keys;
|
||||
var params = this.params;
|
||||
|
||||
for (var i = 1; i < match.length; i++) {
|
||||
var key = keys[i - 1];
|
||||
var prop = key.name;
|
||||
var val = decode_param(match[i])
|
||||
|
||||
if (val !== undefined || !(hasOwnProperty.call(params, prop))) {
|
||||
params[prop] = val;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
};
|
||||
|
||||
/**
|
||||
* Decode param value.
|
||||
*
|
||||
* @param {string} val
|
||||
* @return {string}
|
||||
* @private
|
||||
*/
|
||||
|
||||
function decode_param(val) {
|
||||
if (typeof val !== 'string' || val.length === 0) {
|
||||
return val;
|
||||
}
|
||||
|
||||
try {
|
||||
return decodeURIComponent(val);
|
||||
} catch (err) {
|
||||
if (err instanceof URIError) {
|
||||
err.message = 'Failed to decode param \'' + val + '\'';
|
||||
err.status = err.statusCode = 400;
|
||||
}
|
||||
|
||||
throw err;
|
||||
}
|
||||
}
|
||||
|
|
@ -1,230 +0,0 @@
|
|||
/*!
|
||||
* express
|
||||
* Copyright(c) 2009-2013 TJ Holowaychuk
|
||||
* Copyright(c) 2013 Roman Shtylman
|
||||
* Copyright(c) 2014-2015 Douglas Christopher Wilson
|
||||
* MIT Licensed
|
||||
*/
|
||||
|
||||
'use strict';
|
||||
|
||||
/**
|
||||
* Module dependencies.
|
||||
* @private
|
||||
*/
|
||||
|
||||
var debug = require('debug')('express:router:route');
|
||||
var flatten = require('array-flatten');
|
||||
var Layer = require('./layer');
|
||||
var methods = require('methods');
|
||||
|
||||
/**
|
||||
* Module variables.
|
||||
* @private
|
||||
*/
|
||||
|
||||
var slice = Array.prototype.slice;
|
||||
var toString = Object.prototype.toString;
|
||||
|
||||
/**
|
||||
* Module exports.
|
||||
* @public
|
||||
*/
|
||||
|
||||
module.exports = Route;
|
||||
|
||||
/**
|
||||
* Initialize `Route` with the given `path`,
|
||||
*
|
||||
* @param {String} path
|
||||
* @public
|
||||
*/
|
||||
|
||||
function Route(path) {
|
||||
this.path = path;
|
||||
this.stack = [];
|
||||
|
||||
debug('new %o', path)
|
||||
|
||||
// route handlers for various http methods
|
||||
this.methods = {};
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine if the route handles a given method.
|
||||
* @private
|
||||
*/
|
||||
|
||||
Route.prototype._handles_method = function _handles_method(method) {
|
||||
if (this.methods._all) {
|
||||
return true;
|
||||
}
|
||||
|
||||
// normalize name
|
||||
var name = typeof method === 'string'
|
||||
? method.toLowerCase()
|
||||
: method
|
||||
|
||||
if (name === 'head' && !this.methods['head']) {
|
||||
name = 'get';
|
||||
}
|
||||
|
||||
return Boolean(this.methods[name]);
|
||||
};
|
||||
|
||||
/**
|
||||
* @return {Array} supported HTTP methods
|
||||
* @private
|
||||
*/
|
||||
|
||||
Route.prototype._options = function _options() {
|
||||
var methods = Object.keys(this.methods);
|
||||
|
||||
// append automatic head
|
||||
if (this.methods.get && !this.methods.head) {
|
||||
methods.push('head');
|
||||
}
|
||||
|
||||
for (var i = 0; i < methods.length; i++) {
|
||||
// make upper case
|
||||
methods[i] = methods[i].toUpperCase();
|
||||
}
|
||||
|
||||
return methods;
|
||||
};
|
||||
|
||||
/**
|
||||
* dispatch req, res into this route
|
||||
* @private
|
||||
*/
|
||||
|
||||
Route.prototype.dispatch = function dispatch(req, res, done) {
|
||||
var idx = 0;
|
||||
var stack = this.stack;
|
||||
var sync = 0
|
||||
|
||||
if (stack.length === 0) {
|
||||
return done();
|
||||
}
|
||||
var method = typeof req.method === 'string'
|
||||
? req.method.toLowerCase()
|
||||
: req.method
|
||||
|
||||
if (method === 'head' && !this.methods['head']) {
|
||||
method = 'get';
|
||||
}
|
||||
|
||||
req.route = this;
|
||||
|
||||
next();
|
||||
|
||||
function next(err) {
|
||||
// signal to exit route
|
||||
if (err && err === 'route') {
|
||||
return done();
|
||||
}
|
||||
|
||||
// signal to exit router
|
||||
if (err && err === 'router') {
|
||||
return done(err)
|
||||
}
|
||||
|
||||
// max sync stack
|
||||
if (++sync > 100) {
|
||||
return setImmediate(next, err)
|
||||
}
|
||||
|
||||
var layer = stack[idx++]
|
||||
|
||||
// end of layers
|
||||
if (!layer) {
|
||||
return done(err)
|
||||
}
|
||||
|
||||
if (layer.method && layer.method !== method) {
|
||||
next(err)
|
||||
} else if (err) {
|
||||
layer.handle_error(err, req, res, next);
|
||||
} else {
|
||||
layer.handle_request(req, res, next);
|
||||
}
|
||||
|
||||
sync = 0
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Add a handler for all HTTP verbs to this route.
|
||||
*
|
||||
* Behaves just like middleware and can respond or call `next`
|
||||
* to continue processing.
|
||||
*
|
||||
* You can use multiple `.all` call to add multiple handlers.
|
||||
*
|
||||
* function check_something(req, res, next){
|
||||
* next();
|
||||
* };
|
||||
*
|
||||
* function validate_user(req, res, next){
|
||||
* next();
|
||||
* };
|
||||
*
|
||||
* route
|
||||
* .all(validate_user)
|
||||
* .all(check_something)
|
||||
* .get(function(req, res, next){
|
||||
* res.send('hello world');
|
||||
* });
|
||||
*
|
||||
* @param {function} handler
|
||||
* @return {Route} for chaining
|
||||
* @api public
|
||||
*/
|
||||
|
||||
Route.prototype.all = function all() {
|
||||
var handles = flatten(slice.call(arguments));
|
||||
|
||||
for (var i = 0; i < handles.length; i++) {
|
||||
var handle = handles[i];
|
||||
|
||||
if (typeof handle !== 'function') {
|
||||
var type = toString.call(handle);
|
||||
var msg = 'Route.all() requires a callback function but got a ' + type
|
||||
throw new TypeError(msg);
|
||||
}
|
||||
|
||||
var layer = Layer('/', {}, handle);
|
||||
layer.method = undefined;
|
||||
|
||||
this.methods._all = true;
|
||||
this.stack.push(layer);
|
||||
}
|
||||
|
||||
return this;
|
||||
};
|
||||
|
||||
methods.forEach(function(method){
|
||||
Route.prototype[method] = function(){
|
||||
var handles = flatten(slice.call(arguments));
|
||||
|
||||
for (var i = 0; i < handles.length; i++) {
|
||||
var handle = handles[i];
|
||||
|
||||
if (typeof handle !== 'function') {
|
||||
var type = toString.call(handle);
|
||||
var msg = 'Route.' + method + '() requires a callback function but got a ' + type
|
||||
throw new Error(msg);
|
||||
}
|
||||
|
||||
debug('%s %o', method, this.path)
|
||||
|
||||
var layer = Layer('/', {}, handle);
|
||||
layer.method = method;
|
||||
|
||||
this.methods[method] = true;
|
||||
this.stack.push(layer);
|
||||
}
|
||||
|
||||
return this;
|
||||
};
|
||||
});
|
||||
106
lib/utils.js
106
lib/utils.js
|
|
@ -12,17 +12,20 @@
|
|||
* @api private
|
||||
*/
|
||||
|
||||
var Buffer = require('safe-buffer').Buffer
|
||||
var contentDisposition = require('content-disposition');
|
||||
var { METHODS } = require('node:http');
|
||||
var contentType = require('content-type');
|
||||
var deprecate = require('depd')('express');
|
||||
var flatten = require('array-flatten');
|
||||
var mime = require('send').mime;
|
||||
var etag = require('etag');
|
||||
var mime = require('mime-types')
|
||||
var proxyaddr = require('proxy-addr');
|
||||
var qs = require('qs');
|
||||
var querystring = require('querystring');
|
||||
|
||||
/**
|
||||
* A list of lowercased HTTP methods that are supported by Node.js.
|
||||
* @api private
|
||||
*/
|
||||
exports.methods = METHODS.map((method) => method.toLowerCase());
|
||||
|
||||
/**
|
||||
* Return strong ETag for `body`.
|
||||
*
|
||||
|
|
@ -45,31 +48,6 @@ exports.etag = createETagGenerator({ weak: false })
|
|||
|
||||
exports.wetag = createETagGenerator({ weak: true })
|
||||
|
||||
/**
|
||||
* Check if `path` looks absolute.
|
||||
*
|
||||
* @param {String} path
|
||||
* @return {Boolean}
|
||||
* @api private
|
||||
*/
|
||||
|
||||
exports.isAbsolute = function(path){
|
||||
if ('/' === path[0]) return true;
|
||||
if (':' === path[1] && ('\\' === path[2] || '/' === path[2])) return true; // Windows device path
|
||||
if ('\\\\' === path.substring(0, 2)) return true; // Microsoft Azure absolute path
|
||||
};
|
||||
|
||||
/**
|
||||
* Flatten the given `arr`.
|
||||
*
|
||||
* @param {Array} arr
|
||||
* @return {Array}
|
||||
* @api private
|
||||
*/
|
||||
|
||||
exports.flatten = deprecate.function(flatten,
|
||||
'utils.flatten: use array-flatten npm module instead');
|
||||
|
||||
/**
|
||||
* Normalize the given `type`, for example "html" becomes "text/html".
|
||||
*
|
||||
|
|
@ -81,7 +59,7 @@ exports.flatten = deprecate.function(flatten,
|
|||
exports.normalizeType = function(type){
|
||||
return ~type.indexOf('/')
|
||||
? acceptParams(type)
|
||||
: { value: mime.lookup(type), params: {} };
|
||||
: { value: (mime.lookup(type) || 'application/octet-stream'), params: {} }
|
||||
};
|
||||
|
||||
/**
|
||||
|
|
@ -92,27 +70,10 @@ exports.normalizeType = function(type){
|
|||
* @api private
|
||||
*/
|
||||
|
||||
exports.normalizeTypes = function(types){
|
||||
var ret = [];
|
||||
|
||||
for (var i = 0; i < types.length; ++i) {
|
||||
ret.push(exports.normalizeType(types[i]));
|
||||
}
|
||||
|
||||
return ret;
|
||||
exports.normalizeTypes = function(types) {
|
||||
return types.map(exports.normalizeType);
|
||||
};
|
||||
|
||||
/**
|
||||
* Generate Content-Disposition header appropriate for the filename.
|
||||
* non-ascii filenames are urlencoded and a filename* parameter is added
|
||||
*
|
||||
* @param {String} filename
|
||||
* @return {String}
|
||||
* @api private
|
||||
*/
|
||||
|
||||
exports.contentDisposition = deprecate.function(contentDisposition,
|
||||
'utils.contentDisposition: use content-disposition npm module instead');
|
||||
|
||||
/**
|
||||
* Parse accept params `str` returning an
|
||||
|
|
@ -124,16 +85,33 @@ exports.contentDisposition = deprecate.function(contentDisposition,
|
|||
*/
|
||||
|
||||
function acceptParams (str) {
|
||||
var parts = str.split(/ *; */);
|
||||
var ret = { value: parts[0], quality: 1, params: {} }
|
||||
var length = str.length;
|
||||
var colonIndex = str.indexOf(';');
|
||||
var index = colonIndex === -1 ? length : colonIndex;
|
||||
var ret = { value: str.slice(0, index).trim(), quality: 1, params: {} };
|
||||
|
||||
for (var i = 1; i < parts.length; ++i) {
|
||||
var pms = parts[i].split(/ *= */);
|
||||
if ('q' === pms[0]) {
|
||||
ret.quality = parseFloat(pms[1]);
|
||||
} else {
|
||||
ret.params[pms[0]] = pms[1];
|
||||
while (index < length) {
|
||||
var splitIndex = str.indexOf('=', index);
|
||||
if (splitIndex === -1) break;
|
||||
|
||||
var colonIndex = str.indexOf(';', index);
|
||||
var endIndex = colonIndex === -1 ? length : colonIndex;
|
||||
|
||||
if (splitIndex > endIndex) {
|
||||
index = str.lastIndexOf(';', splitIndex - 1) + 1;
|
||||
continue;
|
||||
}
|
||||
|
||||
var key = str.slice(index, splitIndex).trim();
|
||||
var value = str.slice(splitIndex + 1, endIndex).trim();
|
||||
|
||||
if (key === 'q') {
|
||||
ret.quality = parseFloat(value);
|
||||
} else {
|
||||
ret.params[key] = value;
|
||||
}
|
||||
|
||||
index = endIndex + 1;
|
||||
}
|
||||
|
||||
return ret;
|
||||
|
|
@ -192,7 +170,6 @@ exports.compileQueryParser = function compileQueryParser(val) {
|
|||
fn = querystring.parse;
|
||||
break;
|
||||
case false:
|
||||
fn = newObject;
|
||||
break;
|
||||
case 'extended':
|
||||
fn = parseExtendedQueryString;
|
||||
|
|
@ -290,14 +267,3 @@ function parseExtendedQueryString(str) {
|
|||
allowPrototypes: true
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Return new empty object.
|
||||
*
|
||||
* @return {Object}
|
||||
* @api private
|
||||
*/
|
||||
|
||||
function newObject() {
|
||||
return {};
|
||||
}
|
||||
|
|
|
|||
29
lib/view.js
29
lib/view.js
|
|
@ -14,8 +14,8 @@
|
|||
*/
|
||||
|
||||
var debug = require('debug')('express:view');
|
||||
var path = require('path');
|
||||
var fs = require('fs');
|
||||
var path = require('node:path');
|
||||
var fs = require('node:fs');
|
||||
|
||||
/**
|
||||
* Module variables.
|
||||
|
|
@ -131,8 +131,31 @@ View.prototype.lookup = function lookup(name) {
|
|||
*/
|
||||
|
||||
View.prototype.render = function render(options, callback) {
|
||||
var sync = true;
|
||||
|
||||
debug('render "%s"', this.path);
|
||||
this.engine(this.path, options, callback);
|
||||
|
||||
// render, normalizing sync callbacks
|
||||
this.engine(this.path, options, function onRender() {
|
||||
if (!sync) {
|
||||
return callback.apply(this, arguments);
|
||||
}
|
||||
|
||||
// copy arguments
|
||||
var args = new Array(arguments.length);
|
||||
var cntx = this;
|
||||
|
||||
for (var i = 0; i < arguments.length; i++) {
|
||||
args[i] = arguments[i];
|
||||
}
|
||||
|
||||
// force callback to be async
|
||||
return process.nextTick(function renderTick() {
|
||||
return callback.apply(cntx, args);
|
||||
});
|
||||
});
|
||||
|
||||
sync = false;
|
||||
};
|
||||
|
||||
/**
|
||||
|
|
|
|||
86
package.json
86
package.json
|
|
@ -1,7 +1,7 @@
|
|||
{
|
||||
"name": "express",
|
||||
"description": "Fast, unopinionated, minimalist web framework",
|
||||
"version": "4.19.2",
|
||||
"version": "5.0.1",
|
||||
"author": "TJ Holowaychuk <tj@vision-media.ca>",
|
||||
"contributors": [
|
||||
"Aaron Heckmann <aaron.heckmann+github@gmail.com>",
|
||||
|
|
@ -14,7 +14,11 @@
|
|||
],
|
||||
"license": "MIT",
|
||||
"repository": "expressjs/express",
|
||||
"homepage": "http://expressjs.com/",
|
||||
"homepage": "https://expressjs.com/",
|
||||
"funding": {
|
||||
"type": "opencollective",
|
||||
"url": "https://opencollective.com/express"
|
||||
},
|
||||
"keywords": [
|
||||
"express",
|
||||
"framework",
|
||||
|
|
@ -28,58 +32,54 @@
|
|||
"api"
|
||||
],
|
||||
"dependencies": {
|
||||
"accepts": "~1.3.8",
|
||||
"array-flatten": "1.1.1",
|
||||
"body-parser": "1.20.2",
|
||||
"content-disposition": "0.5.4",
|
||||
"content-type": "~1.0.4",
|
||||
"cookie": "0.6.0",
|
||||
"cookie-signature": "1.0.6",
|
||||
"debug": "2.6.9",
|
||||
"depd": "2.0.0",
|
||||
"encodeurl": "~2.0.0",
|
||||
"escape-html": "~1.0.3",
|
||||
"etag": "~1.8.1",
|
||||
"finalhandler": "1.2.0",
|
||||
"fresh": "0.5.2",
|
||||
"http-errors": "2.0.0",
|
||||
"merge-descriptors": "1.0.3",
|
||||
"methods": "~1.1.2",
|
||||
"on-finished": "2.4.1",
|
||||
"parseurl": "~1.3.3",
|
||||
"path-to-regexp": "0.1.8",
|
||||
"proxy-addr": "~2.0.7",
|
||||
"qs": "6.11.0",
|
||||
"range-parser": "~1.2.1",
|
||||
"safe-buffer": "5.2.1",
|
||||
"send": "0.18.0",
|
||||
"serve-static": "1.15.0",
|
||||
"setprototypeof": "1.2.0",
|
||||
"statuses": "2.0.1",
|
||||
"type-is": "~1.6.18",
|
||||
"utils-merge": "1.0.1",
|
||||
"vary": "~1.1.2"
|
||||
"accepts": "^2.0.0",
|
||||
"body-parser": "^2.1.0",
|
||||
"content-disposition": "^1.0.0",
|
||||
"content-type": "^1.0.5",
|
||||
"cookie": "^0.7.1",
|
||||
"cookie-signature": "^1.2.1",
|
||||
"debug": "^4.4.0",
|
||||
"encodeurl": "^2.0.0",
|
||||
"escape-html": "^1.0.3",
|
||||
"etag": "^1.8.1",
|
||||
"finalhandler": "^2.0.0",
|
||||
"fresh": "^2.0.0",
|
||||
"http-errors": "^2.0.0",
|
||||
"merge-descriptors": "^2.0.0",
|
||||
"mime-types": "^3.0.0",
|
||||
"on-finished": "^2.4.1",
|
||||
"once": "^1.4.0",
|
||||
"parseurl": "^1.3.3",
|
||||
"proxy-addr": "^2.0.7",
|
||||
"qs": "^6.13.0",
|
||||
"range-parser": "^1.2.1",
|
||||
"router": "^2.1.0",
|
||||
"send": "^1.1.0",
|
||||
"serve-static": "^2.1.0",
|
||||
"statuses": "^2.0.1",
|
||||
"type-is": "^2.0.0",
|
||||
"vary": "^1.1.2"
|
||||
},
|
||||
"devDependencies": {
|
||||
"after": "0.8.2",
|
||||
"connect-redis": "3.4.2",
|
||||
"cookie-parser": "1.4.6",
|
||||
"connect-redis": "^8.0.1",
|
||||
"cookie-parser": "1.4.7",
|
||||
"cookie-session": "2.0.0",
|
||||
"ejs": "3.1.9",
|
||||
"ejs": "^3.1.10",
|
||||
"eslint": "8.47.0",
|
||||
"express-session": "1.17.2",
|
||||
"express-session": "^1.18.1",
|
||||
"hbs": "4.2.0",
|
||||
"marked": "0.7.0",
|
||||
"marked": "^15.0.3",
|
||||
"method-override": "3.0.0",
|
||||
"mocha": "10.2.0",
|
||||
"mocha": "^10.7.3",
|
||||
"morgan": "1.10.0",
|
||||
"nyc": "15.1.0",
|
||||
"nyc": "^17.1.0",
|
||||
"pbkdf2-password": "1.2.1",
|
||||
"supertest": "6.3.0",
|
||||
"supertest": "^6.3.0",
|
||||
"vhost": "~3.0.2"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 0.10.0"
|
||||
"node": ">= 18"
|
||||
},
|
||||
"files": [
|
||||
"LICENSE",
|
||||
|
|
@ -90,7 +90,7 @@
|
|||
],
|
||||
"scripts": {
|
||||
"lint": "eslint .",
|
||||
"test": "mocha --require test/support/env --reporter spec --bail --check-leaks test/ test/acceptance/",
|
||||
"test": "mocha --require test/support/env --reporter spec --check-leaks test/ test/acceptance/",
|
||||
"test-ci": "nyc --exclude examples --exclude test --exclude benchmarks --reporter=lcovonly --reporter=text npm test",
|
||||
"test-cov": "nyc --exclude examples --exclude test --exclude benchmarks --reporter=html --reporter=text npm test",
|
||||
"test-tap": "mocha --require test/support/env --reporter tap --check-leaks test/ test/acceptance/"
|
||||
|
|
|
|||
|
|
@ -1,10 +1,10 @@
|
|||
'use strict'
|
||||
|
||||
var after = require('after');
|
||||
var assert = require('assert')
|
||||
var assert = require('node:assert')
|
||||
var express = require('../')
|
||||
, Route = express.Route
|
||||
, methods = require('methods')
|
||||
, methods = require('../lib/utils').methods
|
||||
|
||||
describe('Route', function(){
|
||||
it('should work without handlers', function(done) {
|
||||
|
|
|
|||
200
test/Router.js
200
test/Router.js
|
|
@ -3,11 +3,11 @@
|
|||
var after = require('after');
|
||||
var express = require('../')
|
||||
, Router = express.Router
|
||||
, methods = require('methods')
|
||||
, assert = require('assert');
|
||||
, methods = require('../lib/utils').methods
|
||||
, assert = require('node:assert');
|
||||
|
||||
describe('Router', function(){
|
||||
it('should return a function with router methods', function() {
|
||||
describe('Router', function () {
|
||||
it('should return a function with router methods', function () {
|
||||
var router = new Router();
|
||||
assert(typeof router === 'function')
|
||||
|
||||
|
|
@ -16,32 +16,32 @@ describe('Router', function(){
|
|||
assert(typeof router.use === 'function')
|
||||
});
|
||||
|
||||
it('should support .use of other routers', function(done){
|
||||
it('should support .use of other routers', function (done) {
|
||||
var router = new Router();
|
||||
var another = new Router();
|
||||
|
||||
another.get('/bar', function(req, res){
|
||||
another.get('/bar', function (req, res) {
|
||||
res.end();
|
||||
});
|
||||
router.use('/foo', another);
|
||||
|
||||
router.handle({ url: '/foo/bar', method: 'GET' }, { end: done });
|
||||
router.handle({ url: '/foo/bar', method: 'GET' }, { end: done }, function () { });
|
||||
});
|
||||
|
||||
it('should support dynamic routes', function(done){
|
||||
it('should support dynamic routes', function (done) {
|
||||
var router = new Router();
|
||||
var another = new Router();
|
||||
|
||||
another.get('/:bar', function(req, res){
|
||||
another.get('/:bar', function (req, res) {
|
||||
assert.strictEqual(req.params.bar, 'route')
|
||||
res.end();
|
||||
});
|
||||
router.use('/:foo', another);
|
||||
|
||||
router.handle({ url: '/test/route', method: 'GET' }, { end: done });
|
||||
router.handle({ url: '/test/route', method: 'GET' }, { end: done }, function () { });
|
||||
});
|
||||
|
||||
it('should handle blank URL', function(done){
|
||||
it('should handle blank URL', function (done) {
|
||||
var router = new Router();
|
||||
|
||||
router.use(function (req, res) {
|
||||
|
|
@ -88,10 +88,10 @@ describe('Router', function(){
|
|||
})
|
||||
})
|
||||
|
||||
it('should not stack overflow with many registered routes', function(done){
|
||||
it('should not stack overflow with many registered routes', function (done) {
|
||||
this.timeout(5000) // long-running test
|
||||
|
||||
var handler = function(req, res){ res.end(new Error('wrong handler')) };
|
||||
var handler = function (req, res) { res.end(new Error('wrong handler')) };
|
||||
var router = new Router();
|
||||
|
||||
for (var i = 0; i < 6000; i++) {
|
||||
|
|
@ -102,7 +102,7 @@ describe('Router', function(){
|
|||
res.end();
|
||||
});
|
||||
|
||||
router.handle({ url: '/', method: 'GET' }, { end: done });
|
||||
router.handle({ url: '/', method: 'GET' }, { end: done }, function () { });
|
||||
});
|
||||
|
||||
it('should not stack overflow with a large sync route stack', function (done) {
|
||||
|
|
@ -127,7 +127,9 @@ describe('Router', function(){
|
|||
res.end()
|
||||
})
|
||||
|
||||
router.handle({ url: '/foo', method: 'GET' }, { end: done })
|
||||
router.handle({ url: '/foo', method: 'GET' }, { end: done }, function (err) {
|
||||
assert(!err, err);
|
||||
});
|
||||
})
|
||||
|
||||
it('should not stack overflow with a large sync middleware stack', function (done) {
|
||||
|
|
@ -152,72 +154,74 @@ describe('Router', function(){
|
|||
res.end()
|
||||
})
|
||||
|
||||
router.handle({ url: '/', method: 'GET' }, { end: done })
|
||||
router.handle({ url: '/', method: 'GET' }, { end: done }, function (err) {
|
||||
assert(!err, err);
|
||||
})
|
||||
})
|
||||
|
||||
describe('.handle', function(){
|
||||
it('should dispatch', function(done){
|
||||
describe('.handle', function () {
|
||||
it('should dispatch', function (done) {
|
||||
var router = new Router();
|
||||
|
||||
router.route('/foo').get(function(req, res){
|
||||
router.route('/foo').get(function (req, res) {
|
||||
res.send('foo');
|
||||
});
|
||||
|
||||
var res = {
|
||||
send: function(val) {
|
||||
send: function (val) {
|
||||
assert.strictEqual(val, 'foo')
|
||||
done();
|
||||
}
|
||||
}
|
||||
router.handle({ url: '/foo', method: 'GET' }, res);
|
||||
router.handle({ url: '/foo', method: 'GET' }, res, function () { });
|
||||
})
|
||||
})
|
||||
|
||||
describe('.multiple callbacks', function(){
|
||||
it('should throw if a callback is null', function(){
|
||||
describe('.multiple callbacks', function () {
|
||||
it('should throw if a callback is null', function () {
|
||||
assert.throws(function () {
|
||||
var router = new Router();
|
||||
router.route('/foo').all(null);
|
||||
})
|
||||
})
|
||||
|
||||
it('should throw if a callback is undefined', function(){
|
||||
it('should throw if a callback is undefined', function () {
|
||||
assert.throws(function () {
|
||||
var router = new Router();
|
||||
router.route('/foo').all(undefined);
|
||||
})
|
||||
})
|
||||
|
||||
it('should throw if a callback is not a function', function(){
|
||||
it('should throw if a callback is not a function', function () {
|
||||
assert.throws(function () {
|
||||
var router = new Router();
|
||||
router.route('/foo').all('not a function');
|
||||
})
|
||||
})
|
||||
|
||||
it('should not throw if all callbacks are functions', function(){
|
||||
it('should not throw if all callbacks are functions', function () {
|
||||
var router = new Router();
|
||||
router.route('/foo').all(function(){}).all(function(){});
|
||||
router.route('/foo').all(function () { }).all(function () { });
|
||||
})
|
||||
})
|
||||
|
||||
describe('error', function(){
|
||||
it('should skip non error middleware', function(done){
|
||||
describe('error', function () {
|
||||
it('should skip non error middleware', function (done) {
|
||||
var router = new Router();
|
||||
|
||||
router.get('/foo', function(req, res, next){
|
||||
router.get('/foo', function (req, res, next) {
|
||||
next(new Error('foo'));
|
||||
});
|
||||
|
||||
router.get('/bar', function(req, res, next){
|
||||
router.get('/bar', function (req, res, next) {
|
||||
next(new Error('bar'));
|
||||
});
|
||||
|
||||
router.use(function(req, res, next){
|
||||
router.use(function (req, res, next) {
|
||||
assert(false);
|
||||
});
|
||||
|
||||
router.use(function(err, req, res, next){
|
||||
router.use(function (err, req, res, next) {
|
||||
assert.equal(err.message, 'foo');
|
||||
done();
|
||||
});
|
||||
|
|
@ -225,59 +229,59 @@ describe('Router', function(){
|
|||
router.handle({ url: '/foo', method: 'GET' }, {}, done);
|
||||
});
|
||||
|
||||
it('should handle throwing inside routes with params', function(done) {
|
||||
it('should handle throwing inside routes with params', function (done) {
|
||||
var router = new Router();
|
||||
|
||||
router.get('/foo/:id', function () {
|
||||
throw new Error('foo');
|
||||
});
|
||||
|
||||
router.use(function(req, res, next){
|
||||
router.use(function (req, res, next) {
|
||||
assert(false);
|
||||
});
|
||||
|
||||
router.use(function(err, req, res, next){
|
||||
router.use(function (err, req, res, next) {
|
||||
assert.equal(err.message, 'foo');
|
||||
done();
|
||||
});
|
||||
|
||||
router.handle({ url: '/foo/2', method: 'GET' }, {}, function() {});
|
||||
router.handle({ url: '/foo/2', method: 'GET' }, {}, function () { });
|
||||
});
|
||||
|
||||
it('should handle throwing in handler after async param', function(done) {
|
||||
it('should handle throwing in handler after async param', function (done) {
|
||||
var router = new Router();
|
||||
|
||||
router.param('user', function(req, res, next, val){
|
||||
process.nextTick(function(){
|
||||
router.param('user', function (req, res, next, val) {
|
||||
process.nextTick(function () {
|
||||
req.user = val;
|
||||
next();
|
||||
});
|
||||
});
|
||||
|
||||
router.use('/:user', function(req, res, next){
|
||||
router.use('/:user', function (req, res, next) {
|
||||
throw new Error('oh no!');
|
||||
});
|
||||
|
||||
router.use(function(err, req, res, next){
|
||||
router.use(function (err, req, res, next) {
|
||||
assert.equal(err.message, 'oh no!');
|
||||
done();
|
||||
});
|
||||
|
||||
router.handle({ url: '/bob', method: 'GET' }, {}, function() {});
|
||||
router.handle({ url: '/bob', method: 'GET' }, {}, function () { });
|
||||
});
|
||||
|
||||
it('should handle throwing inside error handlers', function(done) {
|
||||
it('should handle throwing inside error handlers', function (done) {
|
||||
var router = new Router();
|
||||
|
||||
router.use(function(req, res, next){
|
||||
router.use(function (req, res, next) {
|
||||
throw new Error('boom!');
|
||||
});
|
||||
|
||||
router.use(function(err, req, res, next){
|
||||
router.use(function (err, req, res, next) {
|
||||
throw new Error('oops');
|
||||
});
|
||||
|
||||
router.use(function(err, req, res, next){
|
||||
router.use(function (err, req, res, next) {
|
||||
assert.equal(err.message, 'oops');
|
||||
done();
|
||||
});
|
||||
|
|
@ -408,73 +412,55 @@ describe('Router', function(){
|
|||
});
|
||||
})
|
||||
|
||||
describe('.all', function() {
|
||||
it('should support using .all to capture all http verbs', function(done){
|
||||
describe('.all', function () {
|
||||
it('should support using .all to capture all http verbs', function (done) {
|
||||
var router = new Router();
|
||||
|
||||
var count = 0;
|
||||
router.all('/foo', function(){ count++; });
|
||||
router.all('/foo', function () { count++; });
|
||||
|
||||
var url = '/foo?bar=baz';
|
||||
|
||||
methods.forEach(function testMethod(method) {
|
||||
router.handle({ url: url, method: method }, {}, function() {});
|
||||
router.handle({ url: url, method: method }, {}, function () { });
|
||||
});
|
||||
|
||||
assert.equal(count, methods.length);
|
||||
done();
|
||||
})
|
||||
|
||||
it('should be called for any URL when "*"', function (done) {
|
||||
var cb = after(4, done)
|
||||
var router = new Router()
|
||||
|
||||
function no () {
|
||||
throw new Error('should not be called')
|
||||
}
|
||||
|
||||
router.all('*', function (req, res) {
|
||||
res.end()
|
||||
})
|
||||
|
||||
router.handle({ url: '/', method: 'GET' }, { end: cb }, no)
|
||||
router.handle({ url: '/foo', method: 'GET' }, { end: cb }, no)
|
||||
router.handle({ url: 'foo', method: 'GET' }, { end: cb }, no)
|
||||
router.handle({ url: '*', method: 'GET' }, { end: cb }, no)
|
||||
})
|
||||
})
|
||||
|
||||
describe('.use', function() {
|
||||
describe('.use', function () {
|
||||
it('should require middleware', function () {
|
||||
var router = new Router()
|
||||
assert.throws(function () { router.use('/') }, /requires a middleware function/)
|
||||
assert.throws(function () { router.use('/') }, /argument handler is required/)
|
||||
})
|
||||
|
||||
it('should reject string as middleware', function () {
|
||||
var router = new Router()
|
||||
assert.throws(function () { router.use('/', 'foo') }, /requires a middleware function but got a string/)
|
||||
assert.throws(function () { router.use('/', 'foo') }, /argument handler must be a function/)
|
||||
})
|
||||
|
||||
it('should reject number as middleware', function () {
|
||||
var router = new Router()
|
||||
assert.throws(function () { router.use('/', 42) }, /requires a middleware function but got a number/)
|
||||
assert.throws(function () { router.use('/', 42) }, /argument handler must be a function/)
|
||||
})
|
||||
|
||||
it('should reject null as middleware', function () {
|
||||
var router = new Router()
|
||||
assert.throws(function () { router.use('/', null) }, /requires a middleware function but got a Null/)
|
||||
assert.throws(function () { router.use('/', null) }, /argument handler must be a function/)
|
||||
})
|
||||
|
||||
it('should reject Date as middleware', function () {
|
||||
var router = new Router()
|
||||
assert.throws(function () { router.use('/', new Date()) }, /requires a middleware function but got a Date/)
|
||||
assert.throws(function () { router.use('/', new Date()) }, /argument handler must be a function/)
|
||||
})
|
||||
|
||||
it('should be called for any URL', function (done) {
|
||||
var cb = after(4, done)
|
||||
var router = new Router()
|
||||
|
||||
function no () {
|
||||
function no() {
|
||||
throw new Error('should not be called')
|
||||
}
|
||||
|
||||
|
|
@ -488,39 +474,49 @@ describe('Router', function(){
|
|||
router.handle({ url: '*', method: 'GET' }, { end: cb }, no)
|
||||
})
|
||||
|
||||
it('should accept array of middleware', function(done){
|
||||
it('should accept array of middleware', function (done) {
|
||||
var count = 0;
|
||||
var router = new Router();
|
||||
|
||||
function fn1(req, res, next){
|
||||
function fn1(req, res, next) {
|
||||
assert.equal(++count, 1);
|
||||
next();
|
||||
}
|
||||
|
||||
function fn2(req, res, next){
|
||||
function fn2(req, res, next) {
|
||||
assert.equal(++count, 2);
|
||||
next();
|
||||
}
|
||||
|
||||
router.use([fn1, fn2], function(req, res){
|
||||
router.use([fn1, fn2], function (req, res) {
|
||||
assert.equal(++count, 3);
|
||||
done();
|
||||
});
|
||||
|
||||
router.handle({ url: '/foo', method: 'GET' }, {}, function(){});
|
||||
router.handle({ url: '/foo', method: 'GET' }, {}, function () { });
|
||||
})
|
||||
})
|
||||
|
||||
describe('.param', function() {
|
||||
it('should call param function when routing VERBS', function(done) {
|
||||
describe('.param', function () {
|
||||
it('should require function', function () {
|
||||
var router = new Router();
|
||||
assert.throws(router.param.bind(router, 'id'), /argument fn is required/);
|
||||
});
|
||||
|
||||
it('should reject non-function', function () {
|
||||
var router = new Router();
|
||||
assert.throws(router.param.bind(router, 'id', 42), /argument fn must be a function/);
|
||||
});
|
||||
|
||||
it('should call param function when routing VERBS', function (done) {
|
||||
var router = new Router();
|
||||
|
||||
router.param('id', function(req, res, next, id) {
|
||||
router.param('id', function (req, res, next, id) {
|
||||
assert.equal(id, '123');
|
||||
next();
|
||||
});
|
||||
|
||||
router.get('/foo/:id/bar', function(req, res, next) {
|
||||
router.get('/foo/:id/bar', function (req, res, next) {
|
||||
assert.equal(req.params.id, '123');
|
||||
next();
|
||||
});
|
||||
|
|
@ -528,15 +524,15 @@ describe('Router', function(){
|
|||
router.handle({ url: '/foo/123/bar', method: 'get' }, {}, done);
|
||||
});
|
||||
|
||||
it('should call param function when routing middleware', function(done) {
|
||||
it('should call param function when routing middleware', function (done) {
|
||||
var router = new Router();
|
||||
|
||||
router.param('id', function(req, res, next, id) {
|
||||
router.param('id', function (req, res, next, id) {
|
||||
assert.equal(id, '123');
|
||||
next();
|
||||
});
|
||||
|
||||
router.use('/foo/:id/bar', function(req, res, next) {
|
||||
router.use('/foo/:id/bar', function (req, res, next) {
|
||||
assert.equal(req.params.id, '123');
|
||||
assert.equal(req.url, '/baz');
|
||||
next();
|
||||
|
|
@ -545,17 +541,17 @@ describe('Router', function(){
|
|||
router.handle({ url: '/foo/123/bar/baz', method: 'get' }, {}, done);
|
||||
});
|
||||
|
||||
it('should only call once per request', function(done) {
|
||||
it('should only call once per request', function (done) {
|
||||
var count = 0;
|
||||
var req = { url: '/foo/bob/bar', method: 'get' };
|
||||
var router = new Router();
|
||||
var sub = new Router();
|
||||
|
||||
sub.get('/bar', function(req, res, next) {
|
||||
sub.get('/bar', function (req, res, next) {
|
||||
next();
|
||||
});
|
||||
|
||||
router.param('user', function(req, res, next, user) {
|
||||
router.param('user', function (req, res, next, user) {
|
||||
count++;
|
||||
req.user = user;
|
||||
next();
|
||||
|
|
@ -564,7 +560,7 @@ describe('Router', function(){
|
|||
router.use('/foo/:user/', new Router());
|
||||
router.use('/foo/:user/', sub);
|
||||
|
||||
router.handle(req, {}, function(err) {
|
||||
router.handle(req, {}, function (err) {
|
||||
if (err) return done(err);
|
||||
assert.equal(count, 1);
|
||||
assert.equal(req.user, 'bob');
|
||||
|
|
@ -572,17 +568,17 @@ describe('Router', function(){
|
|||
});
|
||||
});
|
||||
|
||||
it('should call when values differ', function(done) {
|
||||
it('should call when values differ', function (done) {
|
||||
var count = 0;
|
||||
var req = { url: '/foo/bob/bar', method: 'get' };
|
||||
var router = new Router();
|
||||
var sub = new Router();
|
||||
|
||||
sub.get('/bar', function(req, res, next) {
|
||||
sub.get('/bar', function (req, res, next) {
|
||||
next();
|
||||
});
|
||||
|
||||
router.param('user', function(req, res, next, user) {
|
||||
router.param('user', function (req, res, next, user) {
|
||||
count++;
|
||||
req.user = user;
|
||||
next();
|
||||
|
|
@ -591,7 +587,7 @@ describe('Router', function(){
|
|||
router.use('/foo/:user/', new Router());
|
||||
router.use('/:user/bob/', sub);
|
||||
|
||||
router.handle(req, {}, function(err) {
|
||||
router.handle(req, {}, function (err) {
|
||||
if (err) return done(err);
|
||||
assert.equal(count, 2);
|
||||
assert.equal(req.user, 'foo');
|
||||
|
|
@ -600,8 +596,8 @@ describe('Router', function(){
|
|||
});
|
||||
});
|
||||
|
||||
describe('parallel requests', function() {
|
||||
it('should not mix requests', function(done) {
|
||||
describe('parallel requests', function () {
|
||||
it('should not mix requests', function (done) {
|
||||
var req1 = { url: '/foo/50/bar', method: 'get' };
|
||||
var req2 = { url: '/foo/10/bar', method: 'get' };
|
||||
var router = new Router();
|
||||
|
|
@ -609,11 +605,11 @@ describe('Router', function(){
|
|||
var cb = after(2, done)
|
||||
|
||||
|
||||
sub.get('/bar', function(req, res, next) {
|
||||
sub.get('/bar', function (req, res, next) {
|
||||
next();
|
||||
});
|
||||
|
||||
router.param('ms', function(req, res, next, ms) {
|
||||
router.param('ms', function (req, res, next, ms) {
|
||||
ms = parseInt(ms, 10);
|
||||
req.ms = ms;
|
||||
setTimeout(next, ms);
|
||||
|
|
@ -622,14 +618,14 @@ describe('Router', function(){
|
|||
router.use('/foo/:ms/', new Router());
|
||||
router.use('/foo/:ms/', sub);
|
||||
|
||||
router.handle(req1, {}, function(err) {
|
||||
router.handle(req1, {}, function (err) {
|
||||
assert.ifError(err);
|
||||
assert.equal(req1.ms, 50);
|
||||
assert.equal(req1.originalUrl, '/foo/50/bar');
|
||||
cb()
|
||||
});
|
||||
|
||||
router.handle(req2, {}, function(err) {
|
||||
router.handle(req2, {}, function (err) {
|
||||
assert.ifError(err);
|
||||
assert.equal(req2.ms, 10);
|
||||
assert.equal(req2.originalUrl, '/foo/10/bar');
|
||||
|
|
|
|||
|
|
@ -26,7 +26,7 @@ describe('app.all()', function(){
|
|||
var app = express()
|
||||
, n = 0;
|
||||
|
||||
app.all('/*', function(req, res, next){
|
||||
app.all('/*splat', function(req, res, next){
|
||||
if (n++) return done(new Error('DELETE called several times'));
|
||||
next();
|
||||
});
|
||||
|
|
|
|||
|
|
@ -1,18 +0,0 @@
|
|||
'use strict'
|
||||
|
||||
var express = require('../')
|
||||
, request = require('supertest');
|
||||
|
||||
describe('app.del()', function(){
|
||||
it('should alias app.delete()', function(done){
|
||||
var app = express();
|
||||
|
||||
app.del('/tobi', function(req, res){
|
||||
res.end('deleted tobi!');
|
||||
});
|
||||
|
||||
request(app)
|
||||
.del('/tobi')
|
||||
.expect('deleted tobi!', done);
|
||||
})
|
||||
})
|
||||
|
|
@ -1,9 +1,9 @@
|
|||
'use strict'
|
||||
|
||||
var assert = require('assert')
|
||||
var assert = require('node:assert')
|
||||
var express = require('../')
|
||||
, fs = require('fs');
|
||||
var path = require('path')
|
||||
, fs = require('node:fs');
|
||||
var path = require('node:path')
|
||||
|
||||
function render(path, options, fn) {
|
||||
fs.readFile(path, 'utf8', function(err, str){
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
var express = require('../');
|
||||
var request = require('supertest');
|
||||
var assert = require('assert');
|
||||
var assert = require('node:assert');
|
||||
|
||||
describe('HEAD', function(){
|
||||
it('should default to GET', function(done){
|
||||
|
|
|
|||
14
test/app.js
14
test/app.js
|
|
@ -1,6 +1,6 @@
|
|||
'use strict'
|
||||
|
||||
var assert = require('assert')
|
||||
var assert = require('node:assert')
|
||||
var express = require('..')
|
||||
var request = require('supertest')
|
||||
|
||||
|
|
@ -56,18 +56,6 @@ describe('app.mountpath', function(){
|
|||
})
|
||||
})
|
||||
|
||||
describe('app.router', function(){
|
||||
it('should throw with notice', function(done){
|
||||
var app = express()
|
||||
|
||||
try {
|
||||
app.router;
|
||||
} catch(err) {
|
||||
done();
|
||||
}
|
||||
})
|
||||
})
|
||||
|
||||
describe('app.path()', function(){
|
||||
it('should return the canonical', function(){
|
||||
var app = express()
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
'use strict'
|
||||
|
||||
var express = require('../')
|
||||
var assert = require('node:assert')
|
||||
|
||||
describe('app.listen()', function(){
|
||||
it('should wrap with an HTTP server', function(done){
|
||||
|
|
@ -10,4 +11,17 @@ describe('app.listen()', function(){
|
|||
server.close(done)
|
||||
});
|
||||
})
|
||||
it('should callback on HTTP server errors', function (done) {
|
||||
var app1 = express()
|
||||
var app2 = express()
|
||||
|
||||
var server1 = app1.listen(0, function (err) {
|
||||
assert(!err)
|
||||
app2.listen(server1.address().port, function (err) {
|
||||
assert(err.code === 'EADDRINUSE')
|
||||
server1.close()
|
||||
done()
|
||||
})
|
||||
})
|
||||
})
|
||||
})
|
||||
|
|
|
|||
|
|
@ -1,14 +1,15 @@
|
|||
'use strict'
|
||||
|
||||
var assert = require('assert')
|
||||
var assert = require('node:assert')
|
||||
var express = require('../')
|
||||
|
||||
describe('app', function(){
|
||||
describe('.locals', function () {
|
||||
it('should default object', function () {
|
||||
it('should default object with null prototype', function () {
|
||||
var app = express()
|
||||
assert.ok(app.locals)
|
||||
assert.strictEqual(typeof app.locals, 'object')
|
||||
assert.strictEqual(Object.getPrototypeOf(app.locals), null)
|
||||
})
|
||||
|
||||
describe('.settings', function () {
|
||||
|
|
|
|||
|
|
@ -7,28 +7,28 @@ describe('OPTIONS', function(){
|
|||
it('should default to the routes defined', function(done){
|
||||
var app = express();
|
||||
|
||||
app.del('/', function(){});
|
||||
app.post('/', function(){});
|
||||
app.get('/users', function(req, res){});
|
||||
app.put('/users', function(req, res){});
|
||||
|
||||
request(app)
|
||||
.options('/users')
|
||||
.expect('Allow', 'GET,HEAD,PUT')
|
||||
.expect(200, 'GET,HEAD,PUT', done);
|
||||
.expect('Allow', 'GET, HEAD, PUT')
|
||||
.expect(200, 'GET, HEAD, PUT', done);
|
||||
})
|
||||
|
||||
it('should only include each method once', function(done){
|
||||
var app = express();
|
||||
|
||||
app.del('/', function(){});
|
||||
app.delete('/', function(){});
|
||||
app.get('/users', function(req, res){});
|
||||
app.put('/users', function(req, res){});
|
||||
app.get('/users', function(req, res){});
|
||||
|
||||
request(app)
|
||||
.options('/users')
|
||||
.expect('Allow', 'GET,HEAD,PUT')
|
||||
.expect(200, 'GET,HEAD,PUT', done);
|
||||
.expect('Allow', 'GET, HEAD, PUT')
|
||||
.expect(200, 'GET, HEAD, PUT', done);
|
||||
})
|
||||
|
||||
it('should not be affected by app.all', function(done){
|
||||
|
|
@ -45,8 +45,8 @@ describe('OPTIONS', function(){
|
|||
request(app)
|
||||
.options('/users')
|
||||
.expect('x-hit', '1')
|
||||
.expect('Allow', 'GET,HEAD,PUT')
|
||||
.expect(200, 'GET,HEAD,PUT', done);
|
||||
.expect('Allow', 'GET, HEAD, PUT')
|
||||
.expect(200, 'GET, HEAD, PUT', done);
|
||||
})
|
||||
|
||||
it('should not respond if the path is not defined', function(done){
|
||||
|
|
@ -69,8 +69,8 @@ describe('OPTIONS', function(){
|
|||
|
||||
request(app)
|
||||
.options('/other')
|
||||
.expect('Allow', 'GET,HEAD')
|
||||
.expect(200, 'GET,HEAD', done);
|
||||
.expect('Allow', 'GET, HEAD')
|
||||
.expect(200, 'GET, HEAD', done);
|
||||
})
|
||||
|
||||
describe('when error occurs in response handler', function () {
|
||||
|
|
|
|||
|
|
@ -1,51 +1,9 @@
|
|||
'use strict'
|
||||
|
||||
var assert = require('assert')
|
||||
var express = require('../')
|
||||
, request = require('supertest');
|
||||
|
||||
describe('app', function(){
|
||||
describe('.param(fn)', function(){
|
||||
it('should map app.param(name, ...) logic', function(done){
|
||||
var app = express();
|
||||
|
||||
app.param(function(name, regexp){
|
||||
if (Object.prototype.toString.call(regexp) === '[object RegExp]') { // See #1557
|
||||
return function(req, res, next, val){
|
||||
var captures;
|
||||
if (captures = regexp.exec(String(val))) {
|
||||
req.params[name] = captures[1];
|
||||
next();
|
||||
} else {
|
||||
next('route');
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
app.param(':name', /^([a-zA-Z]+)$/);
|
||||
|
||||
app.get('/user/:name', function(req, res){
|
||||
res.send(req.params.name);
|
||||
});
|
||||
|
||||
request(app)
|
||||
.get('/user/tj')
|
||||
.expect(200, 'tj', function (err) {
|
||||
if (err) return done(err)
|
||||
request(app)
|
||||
.get('/user/123')
|
||||
.expect(404, done);
|
||||
});
|
||||
|
||||
})
|
||||
|
||||
it('should fail if not given fn', function(){
|
||||
var app = express();
|
||||
assert.throws(app.param.bind(app, ':name', 'bob'))
|
||||
})
|
||||
})
|
||||
|
||||
describe('.param(names, fn)', function(){
|
||||
it('should map the array', function(done){
|
||||
var app = express();
|
||||
|
|
|
|||
|
|
@ -1,8 +1,8 @@
|
|||
'use strict'
|
||||
|
||||
var assert = require('assert')
|
||||
var assert = require('node:assert')
|
||||
var express = require('..');
|
||||
var path = require('path')
|
||||
var path = require('node:path')
|
||||
var tmpl = require('./support/tmpl');
|
||||
|
||||
describe('app', function(){
|
||||
|
|
|
|||
|
|
@ -10,7 +10,7 @@ describe('app', function(){
|
|||
var app = express();
|
||||
|
||||
app.request.querystring = function(){
|
||||
return require('url').parse(this.url).query;
|
||||
return require('node:url').parse(this.url).query;
|
||||
};
|
||||
|
||||
app.use(function(req, res){
|
||||
|
|
|
|||
|
|
@ -61,4 +61,137 @@ describe('app.route', function(){
|
|||
.get('/test')
|
||||
.expect(404, done);
|
||||
});
|
||||
|
||||
describe('promise support', function () {
|
||||
it('should pass rejected promise value', function (done) {
|
||||
var app = express()
|
||||
var route = app.route('/foo')
|
||||
|
||||
route.all(function createError (req, res, next) {
|
||||
return Promise.reject(new Error('boom!'))
|
||||
})
|
||||
|
||||
route.all(function helloWorld (req, res) {
|
||||
res.send('hello, world!')
|
||||
})
|
||||
|
||||
route.all(function handleError (err, req, res, next) {
|
||||
res.status(500)
|
||||
res.send('caught: ' + err.message)
|
||||
})
|
||||
|
||||
request(app)
|
||||
.get('/foo')
|
||||
.expect(500, 'caught: boom!', done)
|
||||
})
|
||||
|
||||
it('should pass rejected promise without value', function (done) {
|
||||
var app = express()
|
||||
var route = app.route('/foo')
|
||||
|
||||
route.all(function createError (req, res, next) {
|
||||
return Promise.reject()
|
||||
})
|
||||
|
||||
route.all(function helloWorld (req, res) {
|
||||
res.send('hello, world!')
|
||||
})
|
||||
|
||||
route.all(function handleError (err, req, res, next) {
|
||||
res.status(500)
|
||||
res.send('caught: ' + err.message)
|
||||
})
|
||||
|
||||
request(app)
|
||||
.get('/foo')
|
||||
.expect(500, 'caught: Rejected promise', done)
|
||||
})
|
||||
|
||||
it('should ignore resolved promise', function (done) {
|
||||
var app = express()
|
||||
var route = app.route('/foo')
|
||||
|
||||
route.all(function createError (req, res, next) {
|
||||
res.send('saw GET /foo')
|
||||
return Promise.resolve('foo')
|
||||
})
|
||||
|
||||
route.all(function () {
|
||||
done(new Error('Unexpected route invoke'))
|
||||
})
|
||||
|
||||
request(app)
|
||||
.get('/foo')
|
||||
.expect(200, 'saw GET /foo', done)
|
||||
})
|
||||
|
||||
describe('error handling', function () {
|
||||
it('should pass rejected promise value', function (done) {
|
||||
var app = express()
|
||||
var route = app.route('/foo')
|
||||
|
||||
route.all(function createError (req, res, next) {
|
||||
return Promise.reject(new Error('boom!'))
|
||||
})
|
||||
|
||||
route.all(function handleError (err, req, res, next) {
|
||||
return Promise.reject(new Error('caught: ' + err.message))
|
||||
})
|
||||
|
||||
route.all(function handleError (err, req, res, next) {
|
||||
res.status(500)
|
||||
res.send('caught again: ' + err.message)
|
||||
})
|
||||
|
||||
request(app)
|
||||
.get('/foo')
|
||||
.expect(500, 'caught again: caught: boom!', done)
|
||||
})
|
||||
|
||||
it('should pass rejected promise without value', function (done) {
|
||||
var app = express()
|
||||
var route = app.route('/foo')
|
||||
|
||||
route.all(function createError (req, res, next) {
|
||||
return Promise.reject(new Error('boom!'))
|
||||
})
|
||||
|
||||
route.all(function handleError (err, req, res, next) {
|
||||
return Promise.reject()
|
||||
})
|
||||
|
||||
route.all(function handleError (err, req, res, next) {
|
||||
res.status(500)
|
||||
res.send('caught again: ' + err.message)
|
||||
})
|
||||
|
||||
request(app)
|
||||
.get('/foo')
|
||||
.expect(500, 'caught again: Rejected promise', done)
|
||||
})
|
||||
|
||||
it('should ignore resolved promise', function (done) {
|
||||
var app = express()
|
||||
var route = app.route('/foo')
|
||||
|
||||
route.all(function createError (req, res, next) {
|
||||
return Promise.reject(new Error('boom!'))
|
||||
})
|
||||
|
||||
route.all(function handleError (err, req, res, next) {
|
||||
res.status(500)
|
||||
res.send('caught: ' + err.message)
|
||||
return Promise.resolve('foo')
|
||||
})
|
||||
|
||||
route.all(function () {
|
||||
done(new Error('Unexpected route invoke'))
|
||||
})
|
||||
|
||||
request(app)
|
||||
.get('/foo')
|
||||
.expect(500, 'caught: boom!', done)
|
||||
})
|
||||
})
|
||||
})
|
||||
});
|
||||
|
|
|
|||
File diff suppressed because it is too large
Load Diff
|
|
@ -1,6 +1,6 @@
|
|||
'use strict'
|
||||
|
||||
var assert = require('assert')
|
||||
var assert = require('node:assert')
|
||||
var express = require('../')
|
||||
, request = require('supertest');
|
||||
|
||||
|
|
@ -51,7 +51,7 @@ describe('app', function(){
|
|||
assert.ok(b)
|
||||
assert.ok(c)
|
||||
assert.ok(!d)
|
||||
res.send(204);
|
||||
res.sendStatus(204);
|
||||
});
|
||||
|
||||
request(app)
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
'use strict'
|
||||
|
||||
var after = require('after');
|
||||
var assert = require('assert')
|
||||
var assert = require('node:assert')
|
||||
var express = require('..');
|
||||
var request = require('supertest');
|
||||
|
||||
|
|
@ -258,27 +258,27 @@ describe('app', function(){
|
|||
describe('.use(path, middleware)', function(){
|
||||
it('should require middleware', function () {
|
||||
var app = express()
|
||||
assert.throws(function () { app.use('/') }, /requires a middleware function/)
|
||||
assert.throws(function () { app.use('/') }, 'TypeError: app.use() requires a middleware function')
|
||||
})
|
||||
|
||||
it('should reject string as middleware', function () {
|
||||
var app = express()
|
||||
assert.throws(function () { app.use('/', 'foo') }, /requires a middleware function but got a string/)
|
||||
assert.throws(function () { app.use('/', 'foo') }, /argument handler must be a function/)
|
||||
})
|
||||
|
||||
it('should reject number as middleware', function () {
|
||||
var app = express()
|
||||
assert.throws(function () { app.use('/', 42) }, /requires a middleware function but got a number/)
|
||||
assert.throws(function () { app.use('/', 42) }, /argument handler must be a function/)
|
||||
})
|
||||
|
||||
it('should reject null as middleware', function () {
|
||||
var app = express()
|
||||
assert.throws(function () { app.use('/', null) }, /requires a middleware function but got a Null/)
|
||||
assert.throws(function () { app.use('/', null) }, /argument handler must be a function/)
|
||||
})
|
||||
|
||||
it('should reject Date as middleware', function () {
|
||||
var app = express()
|
||||
assert.throws(function () { app.use('/', new Date()) }, /requires a middleware function but got a Date/)
|
||||
assert.throws(function () { app.use('/', new Date()) }, /argument handler must be a function/)
|
||||
})
|
||||
|
||||
it('should strip path from req.url', function (done) {
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
'use strict'
|
||||
|
||||
var assert = require('assert');
|
||||
var assert = require('node:assert');
|
||||
var express = require('..');
|
||||
|
||||
describe('config', function () {
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
'use strict'
|
||||
|
||||
var assert = require('assert')
|
||||
var assert = require('node:assert')
|
||||
var express = require('../');
|
||||
var request = require('supertest');
|
||||
|
||||
|
|
@ -79,9 +79,4 @@ describe('exports', function(){
|
|||
.get('/')
|
||||
.expect('bar', done);
|
||||
})
|
||||
|
||||
it('should throw on old middlewares', function(){
|
||||
assert.throws(function () { express.bodyParser() }, /Error:.*middleware.*bodyParser/)
|
||||
assert.throws(function () { express.limit() }, /Error:.*middleware.*limit/)
|
||||
})
|
||||
})
|
||||
|
|
|
|||
|
|
@ -1,15 +1,11 @@
|
|||
'use strict'
|
||||
|
||||
var assert = require('assert')
|
||||
var asyncHooks = tryRequire('async_hooks')
|
||||
var Buffer = require('safe-buffer').Buffer
|
||||
var assert = require('node:assert')
|
||||
var AsyncLocalStorage = require('node:async_hooks').AsyncLocalStorage
|
||||
|
||||
var express = require('..')
|
||||
var request = require('supertest')
|
||||
|
||||
var describeAsyncHooks = typeof asyncHooks.AsyncLocalStorage === 'function'
|
||||
? describe
|
||||
: describe.skip
|
||||
|
||||
describe('express.json()', function () {
|
||||
it('should parse JSON', function (done) {
|
||||
request(createApp())
|
||||
|
|
@ -43,12 +39,13 @@ describe('express.json()', function () {
|
|||
.expect(200, '{}', done)
|
||||
})
|
||||
|
||||
// The old node error message modification in body parser is catching this
|
||||
it('should 400 when only whitespace', function (done) {
|
||||
request(createApp())
|
||||
.post('/')
|
||||
.set('Content-Type', 'application/json')
|
||||
.send(' \n')
|
||||
.expect(400, '[entity.parse.failed] ' + parseError(' '), done)
|
||||
.expect(400, '[entity.parse.failed] ' + parseError(' \n'), done)
|
||||
})
|
||||
|
||||
it('should 400 when invalid content-length', function (done) {
|
||||
|
|
@ -72,32 +69,6 @@ describe('express.json()', function () {
|
|||
.expect(400, /content length/, done)
|
||||
})
|
||||
|
||||
it('should 500 if stream not readable', function (done) {
|
||||
var app = express()
|
||||
|
||||
app.use(function (req, res, next) {
|
||||
req.on('end', next)
|
||||
req.resume()
|
||||
})
|
||||
|
||||
app.use(express.json())
|
||||
|
||||
app.use(function (err, req, res, next) {
|
||||
res.status(err.status || 500)
|
||||
res.send('[' + err.type + '] ' + err.message)
|
||||
})
|
||||
|
||||
app.post('/', function (req, res) {
|
||||
res.json(req.body)
|
||||
})
|
||||
|
||||
request(app)
|
||||
.post('/')
|
||||
.set('Content-Type', 'application/json')
|
||||
.send('{"user":"tobi"}')
|
||||
.expect(500, '[stream.not.readable] stream is not readable', done)
|
||||
})
|
||||
|
||||
it('should handle duplicated middleware', function (done) {
|
||||
var app = express()
|
||||
|
||||
|
|
@ -341,7 +312,7 @@ describe('express.json()', function () {
|
|||
.post('/')
|
||||
.set('Content-Type', 'application/json')
|
||||
.send('{"user":"tobi"}')
|
||||
.expect(200, '{}', done)
|
||||
.expect(200, '', done)
|
||||
})
|
||||
})
|
||||
|
||||
|
|
@ -373,7 +344,7 @@ describe('express.json()', function () {
|
|||
.post('/')
|
||||
.set('Content-Type', 'application/x-json')
|
||||
.send('{"user":"tobi"}')
|
||||
.expect(200, '{}', done)
|
||||
.expect(200, '', done)
|
||||
})
|
||||
})
|
||||
|
||||
|
|
@ -528,13 +499,13 @@ describe('express.json()', function () {
|
|||
})
|
||||
})
|
||||
|
||||
describeAsyncHooks('async local storage', function () {
|
||||
describe('async local storage', function () {
|
||||
before(function () {
|
||||
var app = express()
|
||||
var store = { foo: 'bar' }
|
||||
|
||||
app.use(function (req, res, next) {
|
||||
req.asyncLocalStorage = new asyncHooks.AsyncLocalStorage()
|
||||
req.asyncLocalStorage = new AsyncLocalStorage()
|
||||
req.asyncLocalStorage.run(store, next)
|
||||
})
|
||||
|
||||
|
|
@ -579,14 +550,14 @@ describe('express.json()', function () {
|
|||
.end(done)
|
||||
})
|
||||
|
||||
it('should presist store when unmatched content-type', function (done) {
|
||||
it('should persist store when unmatched content-type', function (done) {
|
||||
request(this.app)
|
||||
.post('/')
|
||||
.set('Content-Type', 'application/fizzbuzz')
|
||||
.send('buzz')
|
||||
.expect(200)
|
||||
.expect('x-store-foo', 'bar')
|
||||
.expect('{}')
|
||||
.expect('')
|
||||
.end(done)
|
||||
})
|
||||
|
||||
|
|
@ -753,6 +724,7 @@ function createApp (options) {
|
|||
app.use(express.json(options))
|
||||
|
||||
app.use(function (err, req, res, next) {
|
||||
// console.log(err)
|
||||
res.status(err.status || 500)
|
||||
res.send(String(req.headers['x-error-property']
|
||||
? err[req.headers['x-error-property']]
|
||||
|
|
@ -780,11 +752,3 @@ function shouldContainInBody (str) {
|
|||
'expected \'' + res.text + '\' to contain \'' + str + '\'')
|
||||
}
|
||||
}
|
||||
|
||||
function tryRequire (name) {
|
||||
try {
|
||||
return require(name)
|
||||
} catch (e) {
|
||||
return {}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,15 +1,11 @@
|
|||
'use strict'
|
||||
|
||||
var assert = require('assert')
|
||||
var asyncHooks = tryRequire('async_hooks')
|
||||
var Buffer = require('safe-buffer').Buffer
|
||||
var assert = require('node:assert')
|
||||
var AsyncLocalStorage = require('node:async_hooks').AsyncLocalStorage
|
||||
|
||||
var express = require('..')
|
||||
var request = require('supertest')
|
||||
|
||||
var describeAsyncHooks = typeof asyncHooks.AsyncLocalStorage === 'function'
|
||||
? describe
|
||||
: describe.skip
|
||||
|
||||
describe('express.raw()', function () {
|
||||
before(function () {
|
||||
this.app = createApp()
|
||||
|
|
@ -65,36 +61,6 @@ describe('express.raw()', function () {
|
|||
.expect(200, { buf: '' }, done)
|
||||
})
|
||||
|
||||
it('should 500 if stream not readable', function (done) {
|
||||
var app = express()
|
||||
|
||||
app.use(function (req, res, next) {
|
||||
req.on('end', next)
|
||||
req.resume()
|
||||
})
|
||||
|
||||
app.use(express.raw())
|
||||
|
||||
app.use(function (err, req, res, next) {
|
||||
res.status(err.status || 500)
|
||||
res.send('[' + err.type + '] ' + err.message)
|
||||
})
|
||||
|
||||
app.post('/', function (req, res) {
|
||||
if (Buffer.isBuffer(req.body)) {
|
||||
res.json({ buf: req.body.toString('hex') })
|
||||
} else {
|
||||
res.json(req.body)
|
||||
}
|
||||
})
|
||||
|
||||
request(app)
|
||||
.post('/')
|
||||
.set('Content-Type', 'application/octet-stream')
|
||||
.send('the user is tobi')
|
||||
.expect(500, '[stream.not.readable] stream is not readable', done)
|
||||
})
|
||||
|
||||
it('should handle duplicated middleware', function (done) {
|
||||
var app = express()
|
||||
|
||||
|
|
@ -236,7 +202,7 @@ describe('express.raw()', function () {
|
|||
var test = request(this.app).post('/')
|
||||
test.set('Content-Type', 'application/octet-stream')
|
||||
test.write(Buffer.from('000102', 'hex'))
|
||||
test.expect(200, '{}', done)
|
||||
test.expect(200, '', done)
|
||||
})
|
||||
})
|
||||
|
||||
|
|
@ -265,7 +231,7 @@ describe('express.raw()', function () {
|
|||
var test = request(this.app).post('/')
|
||||
test.set('Content-Type', 'application/x-foo')
|
||||
test.write(Buffer.from('000102', 'hex'))
|
||||
test.expect(200, '{}', done)
|
||||
test.expect(200, '', done)
|
||||
})
|
||||
})
|
||||
|
||||
|
|
@ -358,13 +324,13 @@ describe('express.raw()', function () {
|
|||
})
|
||||
})
|
||||
|
||||
describeAsyncHooks('async local storage', function () {
|
||||
describe('async local storage', function () {
|
||||
before(function () {
|
||||
var app = express()
|
||||
var store = { foo: 'bar' }
|
||||
|
||||
app.use(function (req, res, next) {
|
||||
req.asyncLocalStorage = new asyncHooks.AsyncLocalStorage()
|
||||
req.asyncLocalStorage = new AsyncLocalStorage()
|
||||
req.asyncLocalStorage.run(store, next)
|
||||
})
|
||||
|
||||
|
|
@ -420,7 +386,6 @@ describe('express.raw()', function () {
|
|||
.send('buzz')
|
||||
.expect(200)
|
||||
.expect('x-store-foo', 'bar')
|
||||
.expect('{}')
|
||||
.end(done)
|
||||
})
|
||||
|
||||
|
|
@ -545,11 +510,3 @@ function createApp (options) {
|
|||
|
||||
return app
|
||||
}
|
||||
|
||||
function tryRequire (name) {
|
||||
try {
|
||||
return require(name)
|
||||
} catch (e) {
|
||||
return {}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,9 +1,8 @@
|
|||
'use strict'
|
||||
|
||||
var assert = require('assert')
|
||||
var Buffer = require('safe-buffer').Buffer
|
||||
var assert = require('node:assert')
|
||||
var express = require('..')
|
||||
var path = require('path')
|
||||
var path = require('node:path')
|
||||
var request = require('supertest')
|
||||
var utils = require('./support/utils')
|
||||
|
||||
|
|
@ -41,7 +40,7 @@ describe('express.static()', function () {
|
|||
it('should set Content-Type', function (done) {
|
||||
request(this.app)
|
||||
.get('/todo.txt')
|
||||
.expect('Content-Type', 'text/plain; charset=UTF-8')
|
||||
.expect('Content-Type', 'text/plain; charset=utf-8')
|
||||
.expect(200, done)
|
||||
})
|
||||
|
||||
|
|
@ -486,7 +485,7 @@ describe('express.static()', function () {
|
|||
request(this.app)
|
||||
.get('/users')
|
||||
.expect('Location', '/users/')
|
||||
.expect(301, /<a href="\/users\/">/, done)
|
||||
.expect(301, /\/users\//, done)
|
||||
})
|
||||
|
||||
it('should redirect directories with query string', function (done) {
|
||||
|
|
@ -508,7 +507,7 @@ describe('express.static()', function () {
|
|||
.get('/snow')
|
||||
.expect('Location', '/snow%20%E2%98%83/')
|
||||
.expect('Content-Type', /html/)
|
||||
.expect(301, />Redirecting to <a href="\/snow%20%E2%98%83\/">\/snow%20%E2%98%83\/<\/a></, done)
|
||||
.expect(301, />Redirecting to \/snow%20%E2%98%83\/</, done)
|
||||
})
|
||||
|
||||
it('should respond with default Content-Security-Policy', function (done) {
|
||||
|
|
|
|||
|
|
@ -1,15 +1,11 @@
|
|||
'use strict'
|
||||
|
||||
var assert = require('assert')
|
||||
var asyncHooks = tryRequire('async_hooks')
|
||||
var Buffer = require('safe-buffer').Buffer
|
||||
var assert = require('node:assert')
|
||||
var AsyncLocalStorage = require('node:async_hooks').AsyncLocalStorage
|
||||
|
||||
var express = require('..')
|
||||
var request = require('supertest')
|
||||
|
||||
var describeAsyncHooks = typeof asyncHooks.AsyncLocalStorage === 'function'
|
||||
? describe
|
||||
: describe.skip
|
||||
|
||||
describe('express.text()', function () {
|
||||
before(function () {
|
||||
this.app = createApp()
|
||||
|
|
@ -61,32 +57,6 @@ describe('express.text()', function () {
|
|||
.expect(200, '""', done)
|
||||
})
|
||||
|
||||
it('should 500 if stream not readable', function (done) {
|
||||
var app = express()
|
||||
|
||||
app.use(function (req, res, next) {
|
||||
req.on('end', next)
|
||||
req.resume()
|
||||
})
|
||||
|
||||
app.use(express.text())
|
||||
|
||||
app.use(function (err, req, res, next) {
|
||||
res.status(err.status || 500)
|
||||
res.send('[' + err.type + '] ' + err.message)
|
||||
})
|
||||
|
||||
app.post('/', function (req, res) {
|
||||
res.json(req.body)
|
||||
})
|
||||
|
||||
request(app)
|
||||
.post('/')
|
||||
.set('Content-Type', 'text/plain')
|
||||
.send('user is tobi')
|
||||
.expect(500, '[stream.not.readable] stream is not readable', done)
|
||||
})
|
||||
|
||||
it('should handle duplicated middleware', function (done) {
|
||||
var app = express()
|
||||
|
||||
|
|
@ -247,7 +217,7 @@ describe('express.text()', function () {
|
|||
.post('/')
|
||||
.set('Content-Type', 'text/plain')
|
||||
.send('user is tobi')
|
||||
.expect(200, '{}', done)
|
||||
.expect(200, '', done)
|
||||
})
|
||||
})
|
||||
|
||||
|
|
@ -277,7 +247,7 @@ describe('express.text()', function () {
|
|||
.post('/')
|
||||
.set('Content-Type', 'text/xml')
|
||||
.send('<user>tobi</user>')
|
||||
.expect(200, '{}', done)
|
||||
.expect(200, '', done)
|
||||
})
|
||||
})
|
||||
|
||||
|
|
@ -387,13 +357,13 @@ describe('express.text()', function () {
|
|||
})
|
||||
})
|
||||
|
||||
describeAsyncHooks('async local storage', function () {
|
||||
describe('async local storage', function () {
|
||||
before(function () {
|
||||
var app = express()
|
||||
var store = { foo: 'bar' }
|
||||
|
||||
app.use(function (req, res, next) {
|
||||
req.asyncLocalStorage = new asyncHooks.AsyncLocalStorage()
|
||||
req.asyncLocalStorage = new AsyncLocalStorage()
|
||||
req.asyncLocalStorage.run(store, next)
|
||||
})
|
||||
|
||||
|
|
@ -445,7 +415,6 @@ describe('express.text()', function () {
|
|||
.send('buzz')
|
||||
.expect(200)
|
||||
.expect('x-store-foo', 'bar')
|
||||
.expect('{}')
|
||||
.end(done)
|
||||
})
|
||||
|
||||
|
|
@ -595,11 +564,3 @@ function createApp (options) {
|
|||
|
||||
return app
|
||||
}
|
||||
|
||||
function tryRequire (name) {
|
||||
try {
|
||||
return require(name)
|
||||
} catch (e) {
|
||||
return {}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,15 +1,11 @@
|
|||
'use strict'
|
||||
|
||||
var assert = require('assert')
|
||||
var asyncHooks = tryRequire('async_hooks')
|
||||
var Buffer = require('safe-buffer').Buffer
|
||||
var assert = require('node:assert')
|
||||
var AsyncLocalStorage = require('node:async_hooks').AsyncLocalStorage
|
||||
|
||||
var express = require('..')
|
||||
var request = require('supertest')
|
||||
|
||||
var describeAsyncHooks = typeof asyncHooks.AsyncLocalStorage === 'function'
|
||||
? describe
|
||||
: describe.skip
|
||||
|
||||
describe('express.urlencoded()', function () {
|
||||
before(function () {
|
||||
this.app = createApp()
|
||||
|
|
@ -62,32 +58,6 @@ describe('express.urlencoded()', function () {
|
|||
.expect(200, '{}', done)
|
||||
})
|
||||
|
||||
it('should 500 if stream not readable', function (done) {
|
||||
var app = express()
|
||||
|
||||
app.use(function (req, res, next) {
|
||||
req.on('end', next)
|
||||
req.resume()
|
||||
})
|
||||
|
||||
app.use(express.urlencoded())
|
||||
|
||||
app.use(function (err, req, res, next) {
|
||||
res.status(err.status || 500)
|
||||
res.send('[' + err.type + '] ' + err.message)
|
||||
})
|
||||
|
||||
app.post('/', function (req, res) {
|
||||
res.json(req.body)
|
||||
})
|
||||
|
||||
request(app)
|
||||
.post('/')
|
||||
.set('Content-Type', 'application/x-www-form-urlencoded')
|
||||
.send('user=tobi')
|
||||
.expect(500, '[stream.not.readable] stream is not readable', done)
|
||||
})
|
||||
|
||||
it('should handle duplicated middleware', function (done) {
|
||||
var app = express()
|
||||
|
||||
|
|
@ -105,12 +75,12 @@ describe('express.urlencoded()', function () {
|
|||
.expect(200, '{"user":"tobi"}', done)
|
||||
})
|
||||
|
||||
it('should parse extended syntax', function (done) {
|
||||
it('should not parse extended syntax', function (done) {
|
||||
request(this.app)
|
||||
.post('/')
|
||||
.set('Content-Type', 'application/x-www-form-urlencoded')
|
||||
.send('user[name][first]=Tobi')
|
||||
.expect(200, '{"user":{"name":{"first":"Tobi"}}}', done)
|
||||
.expect(200, '{"user[name][first]":"Tobi"}', done)
|
||||
})
|
||||
|
||||
describe('with extended option', function () {
|
||||
|
|
@ -212,7 +182,7 @@ describe('express.urlencoded()', function () {
|
|||
it('should parse deep object', function (done) {
|
||||
var str = 'foo'
|
||||
|
||||
for (var i = 0; i < 500; i++) {
|
||||
for (var i = 0; i < 32; i++) {
|
||||
str += '[p]'
|
||||
}
|
||||
|
||||
|
|
@ -230,7 +200,7 @@ describe('express.urlencoded()', function () {
|
|||
var depth = 0
|
||||
var ref = obj.foo
|
||||
while ((ref = ref.p)) { depth++ }
|
||||
assert.strictEqual(depth, 500)
|
||||
assert.strictEqual(depth, 32)
|
||||
})
|
||||
.expect(200, done)
|
||||
})
|
||||
|
|
@ -473,7 +443,7 @@ describe('express.urlencoded()', function () {
|
|||
.post('/')
|
||||
.set('Content-Type', 'application/x-www-form-urlencoded')
|
||||
.send('user=tobi')
|
||||
.expect(200, '{}', done)
|
||||
.expect(200, '', done)
|
||||
})
|
||||
})
|
||||
|
||||
|
|
@ -505,7 +475,7 @@ describe('express.urlencoded()', function () {
|
|||
.post('/')
|
||||
.set('Content-Type', 'application/x-foo')
|
||||
.send('user=tobi')
|
||||
.expect(200, '{}', done)
|
||||
.expect(200, '', done)
|
||||
})
|
||||
})
|
||||
|
||||
|
|
@ -632,13 +602,13 @@ describe('express.urlencoded()', function () {
|
|||
})
|
||||
})
|
||||
|
||||
describeAsyncHooks('async local storage', function () {
|
||||
describe('async local storage', function () {
|
||||
before(function () {
|
||||
var app = express()
|
||||
var store = { foo: 'bar' }
|
||||
|
||||
app.use(function (req, res, next) {
|
||||
req.asyncLocalStorage = new asyncHooks.AsyncLocalStorage()
|
||||
req.asyncLocalStorage = new AsyncLocalStorage()
|
||||
req.asyncLocalStorage.run(store, next)
|
||||
})
|
||||
|
||||
|
|
@ -690,7 +660,6 @@ describe('express.urlencoded()', function () {
|
|||
.send('buzz')
|
||||
.expect(200)
|
||||
.expect('x-store-foo', 'bar')
|
||||
.expect('{}')
|
||||
.end(done)
|
||||
})
|
||||
|
||||
|
|
@ -856,11 +825,3 @@ function expectKeyCount (count) {
|
|||
assert.strictEqual(Object.keys(JSON.parse(res.text)).length, count)
|
||||
}
|
||||
}
|
||||
|
||||
function tryRequire (name) {
|
||||
try {
|
||||
return require(name)
|
||||
} catch (e) {
|
||||
return {}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
'use strict'
|
||||
|
||||
var assert = require('assert')
|
||||
var assert = require('node:assert')
|
||||
var express = require('../');
|
||||
var request = require('supertest');
|
||||
|
||||
|
|
|
|||
|
|
@ -1,50 +0,0 @@
|
|||
'use strict'
|
||||
|
||||
var express = require('../')
|
||||
, request = require('supertest');
|
||||
|
||||
describe('req', function(){
|
||||
describe('.acceptsCharset(type)', function(){
|
||||
describe('when Accept-Charset is not present', function(){
|
||||
it('should return true', function(done){
|
||||
var app = express();
|
||||
|
||||
app.use(function(req, res, next){
|
||||
res.end(req.acceptsCharset('utf-8') ? 'yes' : 'no');
|
||||
});
|
||||
|
||||
request(app)
|
||||
.get('/')
|
||||
.expect('yes', done);
|
||||
})
|
||||
})
|
||||
|
||||
describe('when Accept-Charset is present', function () {
|
||||
it('should return true', function (done) {
|
||||
var app = express();
|
||||
|
||||
app.use(function(req, res, next){
|
||||
res.end(req.acceptsCharset('utf-8') ? 'yes' : 'no');
|
||||
});
|
||||
|
||||
request(app)
|
||||
.get('/')
|
||||
.set('Accept-Charset', 'foo, bar, utf-8')
|
||||
.expect('yes', done);
|
||||
})
|
||||
|
||||
it('should return false otherwise', function(done){
|
||||
var app = express();
|
||||
|
||||
app.use(function(req, res, next){
|
||||
res.end(req.acceptsCharset('utf-8') ? 'yes' : 'no');
|
||||
});
|
||||
|
||||
request(app)
|
||||
.get('/')
|
||||
.set('Accept-Charset', 'foo, bar')
|
||||
.expect('no', done);
|
||||
})
|
||||
})
|
||||
})
|
||||
})
|
||||
|
|
@ -1,39 +0,0 @@
|
|||
'use strict'
|
||||
|
||||
var express = require('../')
|
||||
, request = require('supertest');
|
||||
|
||||
describe('req', function(){
|
||||
describe('.acceptsEncoding', function(){
|
||||
it('should return encoding if accepted', function (done) {
|
||||
var app = express();
|
||||
|
||||
app.get('/', function (req, res) {
|
||||
res.send({
|
||||
gzip: req.acceptsEncoding('gzip'),
|
||||
deflate: req.acceptsEncoding('deflate')
|
||||
})
|
||||
})
|
||||
|
||||
request(app)
|
||||
.get('/')
|
||||
.set('Accept-Encoding', ' gzip, deflate')
|
||||
.expect(200, { gzip: 'gzip', deflate: 'deflate' }, done)
|
||||
})
|
||||
|
||||
it('should be false if encoding not accepted', function(done){
|
||||
var app = express();
|
||||
|
||||
app.get('/', function (req, res) {
|
||||
res.send({
|
||||
bogus: req.acceptsEncoding('bogus')
|
||||
})
|
||||
})
|
||||
|
||||
request(app)
|
||||
.get('/')
|
||||
.set('Accept-Encoding', ' gzip, deflate')
|
||||
.expect(200, { bogus: false }, done)
|
||||
})
|
||||
})
|
||||
})
|
||||
|
|
@ -1,57 +0,0 @@
|
|||
'use strict'
|
||||
|
||||
var express = require('../')
|
||||
, request = require('supertest');
|
||||
|
||||
describe('req', function(){
|
||||
describe('.acceptsLanguage', function(){
|
||||
it('should return language if accepted', function (done) {
|
||||
var app = express();
|
||||
|
||||
app.get('/', function (req, res) {
|
||||
res.send({
|
||||
'en-us': req.acceptsLanguage('en-us'),
|
||||
en: req.acceptsLanguage('en')
|
||||
})
|
||||
})
|
||||
|
||||
request(app)
|
||||
.get('/')
|
||||
.set('Accept-Language', 'en;q=.5, en-us')
|
||||
.expect(200, { 'en-us': 'en-us', en: 'en' }, done)
|
||||
})
|
||||
|
||||
it('should be false if language not accepted', function(done){
|
||||
var app = express();
|
||||
|
||||
app.get('/', function (req, res) {
|
||||
res.send({
|
||||
es: req.acceptsLanguage('es')
|
||||
})
|
||||
})
|
||||
|
||||
request(app)
|
||||
.get('/')
|
||||
.set('Accept-Language', 'en;q=.5, en-us')
|
||||
.expect(200, { es: false }, done)
|
||||
})
|
||||
|
||||
describe('when Accept-Language is not present', function(){
|
||||
it('should always return language', function (done) {
|
||||
var app = express();
|
||||
|
||||
app.get('/', function (req, res) {
|
||||
res.send({
|
||||
en: req.acceptsLanguage('en'),
|
||||
es: req.acceptsLanguage('es'),
|
||||
jp: req.acceptsLanguage('jp')
|
||||
})
|
||||
})
|
||||
|
||||
request(app)
|
||||
.get('/')
|
||||
.expect(200, { en: 'en', es: 'es', jp: 'jp' }, done)
|
||||
})
|
||||
})
|
||||
})
|
||||
})
|
||||
|
|
@ -46,5 +46,25 @@ describe('req', function(){
|
|||
.get('/')
|
||||
.expect(200, 'false', done);
|
||||
})
|
||||
|
||||
it('should ignore "If-Modified-Since" when "If-None-Match" is present', function(done) {
|
||||
var app = express();
|
||||
const etag = '"FooBar"'
|
||||
const now = Date.now()
|
||||
|
||||
app.disable('x-powered-by')
|
||||
app.use(function(req, res) {
|
||||
res.set('Etag', etag)
|
||||
res.set('Last-Modified', new Date(now).toUTCString())
|
||||
res.send(req.fresh);
|
||||
});
|
||||
|
||||
request(app)
|
||||
.get('/')
|
||||
.set('If-Modified-Since', new Date(now - 1000).toUTCString)
|
||||
.set('If-None-Match', etag)
|
||||
.expect(304, done);
|
||||
})
|
||||
|
||||
})
|
||||
})
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
var express = require('../')
|
||||
, request = require('supertest')
|
||||
, assert = require('assert');
|
||||
, assert = require('node:assert');
|
||||
|
||||
describe('req', function(){
|
||||
describe('.get(field)', function(){
|
||||
|
|
|
|||
|
|
@ -28,7 +28,7 @@ describe('req', function(){
|
|||
request(app)
|
||||
.post('/')
|
||||
.set('Host', 'example.com:3000')
|
||||
.expect('example.com', done);
|
||||
.expect(200, 'example.com:3000', done);
|
||||
})
|
||||
|
||||
it('should return undefined otherwise', function(done){
|
||||
|
|
@ -67,7 +67,7 @@ describe('req', function(){
|
|||
request(app)
|
||||
.post('/')
|
||||
.set('Host', '[::1]:3000')
|
||||
.expect('[::1]', done);
|
||||
.expect(200, '[::1]:3000', done);
|
||||
})
|
||||
|
||||
describe('when "trust proxy" is enabled', function(){
|
||||
|
|
|
|||
|
|
@ -1,61 +0,0 @@
|
|||
'use strict'
|
||||
|
||||
var express = require('../')
|
||||
, request = require('supertest')
|
||||
|
||||
describe('req', function(){
|
||||
describe('.param(name, default)', function(){
|
||||
it('should use the default value unless defined', function(done){
|
||||
var app = express();
|
||||
|
||||
app.use(function(req, res){
|
||||
res.end(req.param('name', 'tj'));
|
||||
});
|
||||
|
||||
request(app)
|
||||
.get('/')
|
||||
.expect('tj', done);
|
||||
})
|
||||
})
|
||||
|
||||
describe('.param(name)', function(){
|
||||
it('should check req.query', function(done){
|
||||
var app = express();
|
||||
|
||||
app.use(function(req, res){
|
||||
res.end(req.param('name'));
|
||||
});
|
||||
|
||||
request(app)
|
||||
.get('/?name=tj')
|
||||
.expect('tj', done);
|
||||
})
|
||||
|
||||
it('should check req.body', function(done){
|
||||
var app = express();
|
||||
|
||||
app.use(express.json())
|
||||
|
||||
app.use(function(req, res){
|
||||
res.end(req.param('name'));
|
||||
});
|
||||
|
||||
request(app)
|
||||
.post('/')
|
||||
.send({ name: 'tj' })
|
||||
.expect('tj', done);
|
||||
})
|
||||
|
||||
it('should check req.params', function(done){
|
||||
var app = express();
|
||||
|
||||
app.get('/user/:name', function(req, res){
|
||||
res.end(req.param('filter') + req.param('name'));
|
||||
});
|
||||
|
||||
request(app)
|
||||
.get('/user/tj')
|
||||
.expect('undefinedtj', done);
|
||||
})
|
||||
})
|
||||
})
|
||||
|
|
@ -1,6 +1,6 @@
|
|||
'use strict'
|
||||
|
||||
var assert = require('assert')
|
||||
var assert = require('node:assert')
|
||||
var express = require('../')
|
||||
, request = require('supertest');
|
||||
|
||||
|
|
@ -14,12 +14,12 @@ describe('req', function(){
|
|||
.expect(200, '{}', done);
|
||||
});
|
||||
|
||||
it('should default to parse complex keys', function (done) {
|
||||
it('should default to parse simple keys', function (done) {
|
||||
var app = createApp();
|
||||
|
||||
request(app)
|
||||
.get('/?user[name]=tj')
|
||||
.expect(200, '{"user":{"name":"tj"}}', done);
|
||||
.expect(200, '{"user[name]":"tj"}', done);
|
||||
});
|
||||
|
||||
describe('when "query parser" is extended', function () {
|
||||
|
|
@ -82,23 +82,6 @@ describe('req', function(){
|
|||
});
|
||||
});
|
||||
|
||||
describe('when "query parser fn" is missing', function () {
|
||||
it('should act like "extended"', function (done) {
|
||||
var app = express();
|
||||
|
||||
delete app.settings['query parser'];
|
||||
delete app.settings['query parser fn'];
|
||||
|
||||
app.use(function (req, res) {
|
||||
res.send(req.query);
|
||||
});
|
||||
|
||||
request(app)
|
||||
.get('/?user[name]=tj&user.name=tj')
|
||||
.expect(200, '{"user":{"name":"tj"},"user.name":"tj"}', done);
|
||||
});
|
||||
});
|
||||
|
||||
describe('when "query parser" an unknown value', function () {
|
||||
it('should throw', function () {
|
||||
assert.throws(createApp.bind(null, 'bogus'),
|
||||
|
|
|
|||
|
|
@ -8,7 +8,7 @@ describe('req', function(){
|
|||
it('should be the executed Route', function(done){
|
||||
var app = express();
|
||||
|
||||
app.get('/user/:id/:op?', function(req, res, next){
|
||||
app.get('/user/:id{/:op}', function(req, res, next){
|
||||
res.header('path-1', req.route.path)
|
||||
next();
|
||||
});
|
||||
|
|
@ -20,7 +20,7 @@ describe('req', function(){
|
|||
|
||||
request(app)
|
||||
.get('/user/12/edit')
|
||||
.expect('path-1', '/user/:id/:op?')
|
||||
.expect('path-1', '/user/:id{/:op}')
|
||||
.expect('path-2', '/user/:id/edit')
|
||||
.expect(200, done)
|
||||
})
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
'use strict'
|
||||
|
||||
var assert = require('assert')
|
||||
var assert = require('node:assert')
|
||||
var express = require('..')
|
||||
var request = require('supertest')
|
||||
|
||||
|
|
|
|||
|
|
@ -1,6 +1,5 @@
|
|||
'use strict'
|
||||
|
||||
var Buffer = require('safe-buffer').Buffer
|
||||
var express = require('../')
|
||||
, request = require('supertest');
|
||||
|
||||
|
|
|
|||
|
|
@ -33,35 +33,29 @@ describe('res', function(){
|
|||
.expect(200, done)
|
||||
})
|
||||
|
||||
it('should set expires when passed', function(done) {
|
||||
var expiresAt = new Date()
|
||||
it('should ignore maxAge', function(done){
|
||||
var app = express();
|
||||
|
||||
app.use(function(req, res){
|
||||
res.clearCookie('sid', { expires: expiresAt }).end();
|
||||
res.clearCookie('sid', { path: '/admin', maxAge: 1000 }).end();
|
||||
});
|
||||
|
||||
request(app)
|
||||
.get('/')
|
||||
.expect('Set-Cookie', 'sid=; Path=/; Expires=' + expiresAt.toUTCString() )
|
||||
.expect('Set-Cookie', 'sid=; Path=/admin; Expires=Thu, 01 Jan 1970 00:00:00 GMT')
|
||||
.expect(200, done)
|
||||
})
|
||||
|
||||
it('should set both maxAge and expires when passed', function(done) {
|
||||
var maxAgeInMs = 10000
|
||||
var expiresAt = new Date()
|
||||
var expectedExpires = new Date(expiresAt.getTime() + maxAgeInMs)
|
||||
it('should ignore user supplied expires param', function(done){
|
||||
var app = express();
|
||||
|
||||
app.use(function(req, res){
|
||||
res.clearCookie('sid', { expires: expiresAt, maxAge: maxAgeInMs }).end();
|
||||
res.clearCookie('sid', { path: '/admin', expires: new Date() }).end();
|
||||
});
|
||||
|
||||
request(app)
|
||||
.get('/')
|
||||
// yes, this is the behavior. When we set a max-age, we also set expires to a date 10 sec ahead of expires
|
||||
// even if we set max-age only, we will also set an expires 10 sec in the future
|
||||
.expect('Set-Cookie', 'sid=; Max-Age=10; Path=/; Expires=' + expectedExpires.toUTCString())
|
||||
.expect('Set-Cookie', 'sid=; Path=/admin; Expires=Thu, 01 Jan 1970 00:00:00 GMT')
|
||||
.expect(200, done)
|
||||
})
|
||||
})
|
||||
|
|
|
|||
|
|
@ -3,7 +3,6 @@
|
|||
var express = require('../')
|
||||
, request = require('supertest')
|
||||
, cookieParser = require('cookie-parser')
|
||||
var merge = require('utils-merge');
|
||||
|
||||
describe('res', function(){
|
||||
describe('.cookie(name, object)', function(){
|
||||
|
|
@ -130,7 +129,7 @@ describe('res', function(){
|
|||
var app = express();
|
||||
|
||||
var options = { maxAge: 1000 };
|
||||
var optionsCopy = merge({}, options);
|
||||
var optionsCopy = { ...options };
|
||||
|
||||
app.use(function(req, res){
|
||||
res.cookie('name', 'tobi', options)
|
||||
|
|
|
|||
|
|
@ -1,20 +1,16 @@
|
|||
'use strict'
|
||||
|
||||
var after = require('after');
|
||||
var assert = require('assert')
|
||||
var asyncHooks = tryRequire('async_hooks')
|
||||
var Buffer = require('safe-buffer').Buffer
|
||||
var assert = require('node:assert')
|
||||
var AsyncLocalStorage = require('node:async_hooks').AsyncLocalStorage
|
||||
|
||||
var express = require('..');
|
||||
var path = require('path')
|
||||
var path = require('node:path')
|
||||
var request = require('supertest');
|
||||
var utils = require('./support/utils')
|
||||
|
||||
var FIXTURES_PATH = path.join(__dirname, 'fixtures')
|
||||
|
||||
var describeAsyncHooks = typeof asyncHooks.AsyncLocalStorage === 'function'
|
||||
? describe
|
||||
: describe.skip
|
||||
|
||||
describe('res', function(){
|
||||
describe('.download(path)', function(){
|
||||
it('should transfer as an attachment', function(done){
|
||||
|
|
@ -26,7 +22,7 @@ describe('res', function(){
|
|||
|
||||
request(app)
|
||||
.get('/')
|
||||
.expect('Content-Type', 'text/html; charset=UTF-8')
|
||||
.expect('Content-Type', 'text/html; charset=utf-8')
|
||||
.expect('Content-Disposition', 'attachment; filename="user.html"')
|
||||
.expect(200, '<p>{{user.name}}</p>', done)
|
||||
})
|
||||
|
|
@ -69,7 +65,7 @@ describe('res', function(){
|
|||
|
||||
request(app)
|
||||
.get('/')
|
||||
.expect('Content-Type', 'text/html; charset=UTF-8')
|
||||
.expect('Content-Type', 'text/html; charset=utf-8')
|
||||
.expect('Content-Disposition', 'attachment; filename="document"')
|
||||
.expect(200, done)
|
||||
})
|
||||
|
|
@ -86,19 +82,19 @@ describe('res', function(){
|
|||
|
||||
request(app)
|
||||
.get('/')
|
||||
.expect('Content-Type', 'text/html; charset=UTF-8')
|
||||
.expect('Content-Type', 'text/html; charset=utf-8')
|
||||
.expect('Content-Disposition', 'attachment; filename="user.html"')
|
||||
.expect(200, cb);
|
||||
})
|
||||
|
||||
describeAsyncHooks('async local storage', function () {
|
||||
describe('async local storage', function () {
|
||||
it('should presist store', function (done) {
|
||||
var app = express()
|
||||
var cb = after(2, done)
|
||||
var store = { foo: 'bar' }
|
||||
|
||||
app.use(function (req, res, next) {
|
||||
req.asyncLocalStorage = new asyncHooks.AsyncLocalStorage()
|
||||
req.asyncLocalStorage = new AsyncLocalStorage()
|
||||
req.asyncLocalStorage.run(store, next)
|
||||
})
|
||||
|
||||
|
|
@ -115,7 +111,7 @@ describe('res', function(){
|
|||
|
||||
request(app)
|
||||
.get('/')
|
||||
.expect('Content-Type', 'text/plain; charset=UTF-8')
|
||||
.expect('Content-Type', 'text/plain; charset=utf-8')
|
||||
.expect('Content-Disposition', 'attachment; filename="name.txt"')
|
||||
.expect(200, 'tobi', cb)
|
||||
})
|
||||
|
|
@ -125,7 +121,7 @@ describe('res', function(){
|
|||
var store = { foo: 'bar' }
|
||||
|
||||
app.use(function (req, res, next) {
|
||||
req.asyncLocalStorage = new asyncHooks.AsyncLocalStorage()
|
||||
req.asyncLocalStorage = new AsyncLocalStorage()
|
||||
req.asyncLocalStorage.run(store, next)
|
||||
})
|
||||
|
||||
|
|
@ -369,7 +365,7 @@ describe('res', function(){
|
|||
|
||||
request(app)
|
||||
.get('/')
|
||||
.expect('Content-Type', 'text/html; charset=UTF-8')
|
||||
.expect('Content-Type', 'text/html; charset=utf-8')
|
||||
.expect('Content-Disposition', 'attachment; filename="document"')
|
||||
.expect(200, cb);
|
||||
})
|
||||
|
|
@ -388,7 +384,7 @@ describe('res', function(){
|
|||
request(app)
|
||||
.get('/')
|
||||
.expect(200)
|
||||
.expect('Content-Type', 'text/html; charset=UTF-8')
|
||||
.expect('Content-Type', 'text/html; charset=utf-8')
|
||||
.expect('Content-Disposition', 'attachment; filename="document"')
|
||||
.end(cb)
|
||||
})
|
||||
|
|
@ -488,11 +484,3 @@ describe('res', function(){
|
|||
})
|
||||
})
|
||||
})
|
||||
|
||||
function tryRequire (name) {
|
||||
try {
|
||||
return require(name)
|
||||
} catch (e) {
|
||||
return {}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -3,7 +3,7 @@
|
|||
var after = require('after')
|
||||
var express = require('../')
|
||||
, request = require('supertest')
|
||||
, assert = require('assert');
|
||||
, assert = require('node:assert');
|
||||
|
||||
var app1 = express();
|
||||
|
||||
|
|
@ -28,7 +28,8 @@ app1.use(function(req, res, next){
|
|||
|
||||
app1.use(function(err, req, res, next){
|
||||
if (!err.types) throw err;
|
||||
res.send(err.status, 'Supports: ' + err.types.join(', '));
|
||||
res.status(err.status)
|
||||
res.send('Supports: ' + err.types.join(', '))
|
||||
})
|
||||
|
||||
var app2 = express();
|
||||
|
|
@ -42,7 +43,8 @@ app2.use(function(req, res, next){
|
|||
});
|
||||
|
||||
app2.use(function(err, req, res, next){
|
||||
res.send(err.status, 'Supports: ' + err.types.join(', '));
|
||||
res.status(err.status)
|
||||
res.send('Supports: ' + err.types.join(', '))
|
||||
})
|
||||
|
||||
var app3 = express();
|
||||
|
|
@ -70,7 +72,8 @@ app4.get('/', function (req, res) {
|
|||
});
|
||||
|
||||
app4.use(function(err, req, res, next){
|
||||
res.send(err.status, 'Supports: ' + err.types.join(', '));
|
||||
res.status(err.status)
|
||||
res.send('Supports: ' + err.types.join(', '))
|
||||
})
|
||||
|
||||
var app5 = express();
|
||||
|
|
@ -103,7 +106,8 @@ describe('res', function(){
|
|||
});
|
||||
|
||||
app.use(function(err, req, res, next){
|
||||
res.send(err.status, 'Supports: ' + err.types.join(', '));
|
||||
res.status(err.status)
|
||||
res.send('Supports: ' + err.types.join(', '))
|
||||
});
|
||||
|
||||
test(app);
|
||||
|
|
@ -164,7 +168,8 @@ describe('res', function(){
|
|||
});
|
||||
|
||||
router.use(function(err, req, res, next){
|
||||
res.send(err.status, 'Supports: ' + err.types.join(', '));
|
||||
res.status(err.status)
|
||||
res.send('Supports: ' + err.types.join(', '))
|
||||
})
|
||||
|
||||
app.use(router)
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
var express = require('../')
|
||||
, request = require('supertest')
|
||||
, assert = require('assert');
|
||||
, assert = require('node:assert');
|
||||
|
||||
describe('res', function(){
|
||||
describe('.json(object)', function(){
|
||||
|
|
@ -183,47 +183,4 @@ describe('res', function(){
|
|||
})
|
||||
})
|
||||
})
|
||||
|
||||
describe('.json(status, object)', function(){
|
||||
it('should respond with json and set the .statusCode', function(done){
|
||||
var app = express();
|
||||
|
||||
app.use(function(req, res){
|
||||
res.json(201, { id: 1 });
|
||||
});
|
||||
|
||||
request(app)
|
||||
.get('/')
|
||||
.expect('Content-Type', 'application/json; charset=utf-8')
|
||||
.expect(201, '{"id":1}', done)
|
||||
})
|
||||
})
|
||||
|
||||
describe('.json(object, status)', function(){
|
||||
it('should respond with json and set the .statusCode for backwards compat', function(done){
|
||||
var app = express();
|
||||
|
||||
app.use(function(req, res){
|
||||
res.json({ id: 1 }, 201);
|
||||
});
|
||||
|
||||
request(app)
|
||||
.get('/')
|
||||
.expect('Content-Type', 'application/json; charset=utf-8')
|
||||
.expect(201, '{"id":1}', done)
|
||||
})
|
||||
|
||||
it('should use status as second number for backwards compat', function(done){
|
||||
var app = express();
|
||||
|
||||
app.use(function(req, res){
|
||||
res.json(200, 201);
|
||||
});
|
||||
|
||||
request(app)
|
||||
.get('/')
|
||||
.expect('Content-Type', 'application/json; charset=utf-8')
|
||||
.expect(201, '200', done)
|
||||
})
|
||||
})
|
||||
})
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
var express = require('../')
|
||||
, request = require('supertest')
|
||||
, assert = require('assert');
|
||||
, assert = require('node:assert');
|
||||
var utils = require('./support/utils');
|
||||
|
||||
describe('res', function(){
|
||||
|
|
@ -328,49 +328,6 @@ describe('res', function(){
|
|||
})
|
||||
})
|
||||
|
||||
describe('.jsonp(status, object)', function(){
|
||||
it('should respond with json and set the .statusCode', function(done){
|
||||
var app = express();
|
||||
|
||||
app.use(function(req, res){
|
||||
res.jsonp(201, { id: 1 });
|
||||
});
|
||||
|
||||
request(app)
|
||||
.get('/')
|
||||
.expect('Content-Type', 'application/json; charset=utf-8')
|
||||
.expect(201, '{"id":1}', done)
|
||||
})
|
||||
})
|
||||
|
||||
describe('.jsonp(object, status)', function(){
|
||||
it('should respond with json and set the .statusCode for backwards compat', function(done){
|
||||
var app = express();
|
||||
|
||||
app.use(function(req, res){
|
||||
res.jsonp({ id: 1 }, 201);
|
||||
});
|
||||
|
||||
request(app)
|
||||
.get('/')
|
||||
.expect('Content-Type', 'application/json; charset=utf-8')
|
||||
.expect(201, '{"id":1}', done)
|
||||
})
|
||||
|
||||
it('should use status as second number for backwards compat', function(done){
|
||||
var app = express();
|
||||
|
||||
app.use(function(req, res){
|
||||
res.jsonp(200, 201);
|
||||
});
|
||||
|
||||
request(app)
|
||||
.get('/')
|
||||
.expect('Content-Type', 'application/json; charset=utf-8')
|
||||
.expect(201, '200', done)
|
||||
})
|
||||
})
|
||||
|
||||
it('should not override previous Content-Types', function(done){
|
||||
var app = express();
|
||||
|
||||
|
|
|
|||
|
|
@ -43,5 +43,23 @@ describe('res', function(){
|
|||
.expect('Link', '<http://api.example.com/users?page=2>; rel="next", <http://api.example.com/users?page=5>; rel="last", <http://api.example.com/users?page=1>; rel="prev"')
|
||||
.expect(200, done);
|
||||
})
|
||||
|
||||
it('should set multiple links for single rel', function (done) {
|
||||
var app = express();
|
||||
|
||||
app.use(function (req, res) {
|
||||
res.links({
|
||||
next: 'http://api.example.com/users?page=2',
|
||||
last: ['http://api.example.com/users?page=5', 'http://api.example.com/users?page=1']
|
||||
});
|
||||
|
||||
res.end();
|
||||
});
|
||||
|
||||
request(app)
|
||||
.get('/')
|
||||
.expect('Link', '<http://api.example.com/users?page=2>; rel="next", <http://api.example.com/users?page=5>; rel="last", <http://api.example.com/users?page=1>; rel="last"')
|
||||
.expect(200, done);
|
||||
})
|
||||
})
|
||||
})
|
||||
|
|
|
|||
|
|
@ -2,8 +2,8 @@
|
|||
|
||||
var express = require('../')
|
||||
, request = require('supertest')
|
||||
, assert = require('assert')
|
||||
, url = require('url');
|
||||
, assert = require('node:assert')
|
||||
, url = require('node:url');
|
||||
|
||||
describe('res', function(){
|
||||
describe('.location(url)', function(){
|
||||
|
|
@ -46,65 +46,19 @@ describe('res', function(){
|
|||
.expect(200, done)
|
||||
})
|
||||
|
||||
describe('when url is "back"', function () {
|
||||
it('should set location from "Referer" header', function (done) {
|
||||
var app = express()
|
||||
it('should encode data uri1', function (done) {
|
||||
var app = express()
|
||||
app.use(function (req, res) {
|
||||
res.location('data:text/javascript,export default () => { }').end();
|
||||
});
|
||||
|
||||
app.use(function (req, res) {
|
||||
res.location('back').end()
|
||||
})
|
||||
|
||||
request(app)
|
||||
request(app)
|
||||
.get('/')
|
||||
.set('Referer', '/some/page.html')
|
||||
.expect('Location', '/some/page.html')
|
||||
.expect('Location', 'data:text/javascript,export%20default%20()%20=%3E%20%7B%20%7D')
|
||||
.expect(200, done)
|
||||
})
|
||||
|
||||
it('should set location from "Referrer" header', function (done) {
|
||||
var app = express()
|
||||
|
||||
app.use(function (req, res) {
|
||||
res.location('back').end()
|
||||
})
|
||||
|
||||
request(app)
|
||||
.get('/')
|
||||
.set('Referrer', '/some/page.html')
|
||||
.expect('Location', '/some/page.html')
|
||||
.expect(200, done)
|
||||
})
|
||||
|
||||
it('should prefer "Referrer" header', function (done) {
|
||||
var app = express()
|
||||
|
||||
app.use(function (req, res) {
|
||||
res.location('back').end()
|
||||
})
|
||||
|
||||
request(app)
|
||||
.get('/')
|
||||
.set('Referer', '/some/page1.html')
|
||||
.set('Referrer', '/some/page2.html')
|
||||
.expect('Location', '/some/page2.html')
|
||||
.expect(200, done)
|
||||
})
|
||||
|
||||
it('should set the header to "/" without referrer', function (done) {
|
||||
var app = express()
|
||||
|
||||
app.use(function (req, res) {
|
||||
res.location('back').end()
|
||||
})
|
||||
|
||||
request(app)
|
||||
.get('/')
|
||||
.expect('Location', '/')
|
||||
.expect(200, done)
|
||||
})
|
||||
})
|
||||
|
||||
it('should encode data uri', function (done) {
|
||||
it('should encode data uri2', function (done) {
|
||||
var app = express()
|
||||
app.use(function (req, res) {
|
||||
res.location('data:text/javascript,export default () => { }').end();
|
||||
|
|
|
|||
|
|
@ -61,21 +61,6 @@ describe('res', function(){
|
|||
})
|
||||
})
|
||||
|
||||
describe('.redirect(url, status)', function(){
|
||||
it('should set the response status', function(done){
|
||||
var app = express();
|
||||
|
||||
app.use(function(req, res){
|
||||
res.redirect('http://google.com', 303);
|
||||
});
|
||||
|
||||
request(app)
|
||||
.get('/')
|
||||
.expect('Location', 'http://google.com')
|
||||
.expect(303, done)
|
||||
})
|
||||
})
|
||||
|
||||
describe('when the request method is HEAD', function(){
|
||||
it('should ignore the body', function(done){
|
||||
var app = express();
|
||||
|
|
@ -106,7 +91,7 @@ describe('res', function(){
|
|||
.set('Accept', 'text/html')
|
||||
.expect('Content-Type', /html/)
|
||||
.expect('Location', 'http://google.com')
|
||||
.expect(302, '<p>Found. Redirecting to <a href="http://google.com">http://google.com</a></p>', done)
|
||||
.expect(302, '<p>Found. Redirecting to http://google.com</p>', done)
|
||||
})
|
||||
|
||||
it('should escape the url', function(done){
|
||||
|
|
@ -122,9 +107,27 @@ describe('res', function(){
|
|||
.set('Accept', 'text/html')
|
||||
.expect('Content-Type', /html/)
|
||||
.expect('Location', '%3Cla\'me%3E')
|
||||
.expect(302, '<p>Found. Redirecting to <a href="%3Cla'me%3E">%3Cla'me%3E</a></p>', done)
|
||||
.expect(302, '<p>Found. Redirecting to %3Cla'me%3E</p>', done)
|
||||
})
|
||||
|
||||
it('should not render evil javascript links in anchor href (prevent XSS)', function(done){
|
||||
var app = express();
|
||||
var xss = 'javascript:eval(document.body.innerHTML=`<p>XSS</p>`);';
|
||||
var encodedXss = 'javascript:eval(document.body.innerHTML=%60%3Cp%3EXSS%3C/p%3E%60);';
|
||||
|
||||
app.use(function(req, res){
|
||||
res.redirect(xss);
|
||||
});
|
||||
|
||||
request(app)
|
||||
.get('/')
|
||||
.set('Host', 'http://example.com')
|
||||
.set('Accept', 'text/html')
|
||||
.expect('Content-Type', /html/)
|
||||
.expect('Location', encodedXss)
|
||||
.expect(302, '<p>Found. Redirecting to ' + encodedXss +'</p>', done);
|
||||
});
|
||||
|
||||
it('should include the redirect type', function(done){
|
||||
var app = express();
|
||||
|
||||
|
|
@ -137,7 +140,7 @@ describe('res', function(){
|
|||
.set('Accept', 'text/html')
|
||||
.expect('Content-Type', /html/)
|
||||
.expect('Location', 'http://google.com')
|
||||
.expect(301, '<p>Moved Permanently. Redirecting to <a href="http://google.com">http://google.com</a></p>', done);
|
||||
.expect(301, '<p>Moved Permanently. Redirecting to http://google.com</p>', done);
|
||||
})
|
||||
})
|
||||
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
'use strict'
|
||||
|
||||
var express = require('..');
|
||||
var path = require('path')
|
||||
var path = require('node:path')
|
||||
var request = require('supertest');
|
||||
var tmpl = require('./support/tmpl');
|
||||
|
||||
|
|
|
|||
|
|
@ -1,9 +1,8 @@
|
|||
'use strict'
|
||||
|
||||
var assert = require('assert')
|
||||
var Buffer = require('safe-buffer').Buffer
|
||||
var assert = require('node:assert')
|
||||
var express = require('..');
|
||||
var methods = require('methods');
|
||||
var methods = require('../lib/utils').methods;
|
||||
var request = require('supertest');
|
||||
var utils = require('./support/utils');
|
||||
|
||||
|
|
@ -53,63 +52,18 @@ describe('res', function(){
|
|||
})
|
||||
})
|
||||
|
||||
describe('.send(code)', function(){
|
||||
it('should set .statusCode', function(done){
|
||||
describe('.send(Number)', function(){
|
||||
it('should send as application/json', function(done){
|
||||
var app = express();
|
||||
|
||||
app.use(function(req, res){
|
||||
res.send(201)
|
||||
});
|
||||
|
||||
request(app)
|
||||
.get('/')
|
||||
.expect('Created')
|
||||
.expect(201, done);
|
||||
})
|
||||
})
|
||||
|
||||
describe('.send(code, body)', function(){
|
||||
it('should set .statusCode and body', function(done){
|
||||
var app = express();
|
||||
|
||||
app.use(function(req, res){
|
||||
res.send(201, 'Created :)');
|
||||
});
|
||||
|
||||
request(app)
|
||||
.get('/')
|
||||
.expect('Created :)')
|
||||
.expect(201, done);
|
||||
})
|
||||
})
|
||||
|
||||
describe('.send(body, code)', function(){
|
||||
it('should be supported for backwards compat', function(done){
|
||||
var app = express();
|
||||
|
||||
app.use(function(req, res){
|
||||
res.send('Bad!', 400);
|
||||
});
|
||||
|
||||
request(app)
|
||||
.get('/')
|
||||
.expect('Bad!')
|
||||
.expect(400, done);
|
||||
})
|
||||
})
|
||||
|
||||
describe('.send(code, number)', function(){
|
||||
it('should send number as json', function(done){
|
||||
var app = express();
|
||||
|
||||
app.use(function(req, res){
|
||||
res.send(200, 0.123);
|
||||
res.send(1000);
|
||||
});
|
||||
|
||||
request(app)
|
||||
.get('/')
|
||||
.expect('Content-Type', 'application/json; charset=utf-8')
|
||||
.expect(200, '0.123', done);
|
||||
.expect(200, '1000', done)
|
||||
})
|
||||
})
|
||||
|
||||
|
|
@ -223,6 +177,19 @@ describe('res', function(){
|
|||
.expect(200, 'hey', done);
|
||||
})
|
||||
|
||||
it('should accept Uint8Array', function(done){
|
||||
var app = express();
|
||||
app.use(function(req, res){
|
||||
const encodedHey = new TextEncoder().encode("hey");
|
||||
res.set("Content-Type", "text/plain").send(encodedHey);
|
||||
})
|
||||
|
||||
request(app)
|
||||
.get("/")
|
||||
.expect("Content-Type", "text/plain; charset=utf-8")
|
||||
.expect(200, "hey", done);
|
||||
})
|
||||
|
||||
it('should not override ETag', function (done) {
|
||||
var app = express()
|
||||
|
||||
|
|
@ -463,7 +430,7 @@ describe('res', function(){
|
|||
|
||||
app.use(function (req, res) {
|
||||
res.set('etag', '"asdf"');
|
||||
res.send(200);
|
||||
res.send('hello!');
|
||||
});
|
||||
|
||||
app.enable('etag');
|
||||
|
|
@ -514,7 +481,7 @@ describe('res', function(){
|
|||
|
||||
app.use(function (req, res) {
|
||||
res.set('etag', '"asdf"');
|
||||
res.send(200);
|
||||
res.send('hello!');
|
||||
});
|
||||
|
||||
request(app)
|
||||
|
|
|
|||
|
|
@ -1,20 +1,16 @@
|
|||
'use strict'
|
||||
|
||||
var after = require('after');
|
||||
var asyncHooks = tryRequire('async_hooks')
|
||||
var Buffer = require('safe-buffer').Buffer
|
||||
var assert = require('node:assert')
|
||||
var AsyncLocalStorage = require('node:async_hooks').AsyncLocalStorage
|
||||
|
||||
var express = require('../')
|
||||
, request = require('supertest')
|
||||
, assert = require('assert');
|
||||
var onFinished = require('on-finished');
|
||||
var path = require('path');
|
||||
var path = require('node:path');
|
||||
var fixtures = path.join(__dirname, 'fixtures');
|
||||
var utils = require('./support/utils');
|
||||
|
||||
var describeAsyncHooks = typeof asyncHooks.AsyncLocalStorage === 'function'
|
||||
? describe
|
||||
: describe.skip
|
||||
|
||||
describe('res', function(){
|
||||
describe('.sendFile(path)', function () {
|
||||
it('should error missing path', function (done) {
|
||||
|
|
@ -82,6 +78,19 @@ describe('res', function(){
|
|||
});
|
||||
});
|
||||
|
||||
it('should disable the ETag function if requested', function (done) {
|
||||
var app = createApp(path.resolve(fixtures, 'name.txt')).disable('etag');
|
||||
|
||||
request(app)
|
||||
.get('/')
|
||||
.expect(handleHeaders)
|
||||
.expect(200, done);
|
||||
|
||||
function handleHeaders (res) {
|
||||
assert(res.headers.etag === undefined);
|
||||
}
|
||||
});
|
||||
|
||||
it('should 404 for directory', function (done) {
|
||||
var app = createApp(path.resolve(fixtures, 'blog'));
|
||||
|
||||
|
|
@ -267,14 +276,14 @@ describe('res', function(){
|
|||
.expect(200, 'got 404 error', done)
|
||||
})
|
||||
|
||||
describeAsyncHooks('async local storage', function () {
|
||||
describe('async local storage', function () {
|
||||
it('should presist store', function (done) {
|
||||
var app = express()
|
||||
var cb = after(2, done)
|
||||
var store = { foo: 'bar' }
|
||||
|
||||
app.use(function (req, res, next) {
|
||||
req.asyncLocalStorage = new asyncHooks.AsyncLocalStorage()
|
||||
req.asyncLocalStorage = new AsyncLocalStorage()
|
||||
req.asyncLocalStorage.run(store, next)
|
||||
})
|
||||
|
||||
|
|
@ -291,7 +300,7 @@ describe('res', function(){
|
|||
|
||||
request(app)
|
||||
.get('/')
|
||||
.expect('Content-Type', 'text/plain; charset=UTF-8')
|
||||
.expect('Content-Type', 'text/plain; charset=utf-8')
|
||||
.expect(200, 'tobi', cb)
|
||||
})
|
||||
|
||||
|
|
@ -300,7 +309,7 @@ describe('res', function(){
|
|||
var store = { foo: 'bar' }
|
||||
|
||||
app.use(function (req, res, next) {
|
||||
req.asyncLocalStorage = new asyncHooks.AsyncLocalStorage()
|
||||
req.asyncLocalStorage = new AsyncLocalStorage()
|
||||
req.asyncLocalStorage.run(store, next)
|
||||
})
|
||||
|
||||
|
|
@ -890,507 +899,6 @@ describe('res', function(){
|
|||
})
|
||||
})
|
||||
})
|
||||
|
||||
describe('.sendfile(path, fn)', function(){
|
||||
it('should invoke the callback when complete', function(done){
|
||||
var app = express();
|
||||
var cb = after(2, done);
|
||||
|
||||
app.use(function(req, res){
|
||||
res.sendfile('test/fixtures/user.html', cb)
|
||||
});
|
||||
|
||||
request(app)
|
||||
.get('/')
|
||||
.expect(200, cb);
|
||||
})
|
||||
|
||||
it('should utilize the same options as express.static()', function(done){
|
||||
var app = express();
|
||||
|
||||
app.use(function(req, res){
|
||||
res.sendfile('test/fixtures/user.html', { maxAge: 60000 });
|
||||
});
|
||||
|
||||
request(app)
|
||||
.get('/')
|
||||
.expect('Cache-Control', 'public, max-age=60')
|
||||
.end(done);
|
||||
})
|
||||
|
||||
it('should invoke the callback when client aborts', function (done) {
|
||||
var cb = after(2, done)
|
||||
var app = express();
|
||||
|
||||
app.use(function (req, res) {
|
||||
setImmediate(function () {
|
||||
res.sendfile('test/fixtures/name.txt', function (err) {
|
||||
assert.ok(err)
|
||||
assert.strictEqual(err.code, 'ECONNABORTED')
|
||||
cb()
|
||||
});
|
||||
});
|
||||
test.req.abort()
|
||||
});
|
||||
|
||||
var server = app.listen()
|
||||
var test = request(server).get('/')
|
||||
test.end(function (err) {
|
||||
assert.ok(err)
|
||||
server.close(cb)
|
||||
})
|
||||
})
|
||||
|
||||
it('should invoke the callback when client already aborted', function (done) {
|
||||
var cb = after(2, done)
|
||||
var app = express();
|
||||
|
||||
app.use(function (req, res) {
|
||||
onFinished(res, function () {
|
||||
res.sendfile('test/fixtures/name.txt', function (err) {
|
||||
assert.ok(err)
|
||||
assert.strictEqual(err.code, 'ECONNABORTED')
|
||||
cb()
|
||||
});
|
||||
});
|
||||
test.req.abort()
|
||||
});
|
||||
|
||||
var server = app.listen()
|
||||
var test = request(server).get('/')
|
||||
test.end(function (err) {
|
||||
assert.ok(err)
|
||||
server.close(cb)
|
||||
})
|
||||
})
|
||||
|
||||
it('should invoke the callback without error when HEAD', function (done) {
|
||||
var app = express();
|
||||
var cb = after(2, done);
|
||||
|
||||
app.use(function (req, res) {
|
||||
res.sendfile('test/fixtures/name.txt', cb);
|
||||
});
|
||||
|
||||
request(app)
|
||||
.head('/')
|
||||
.expect(200, cb);
|
||||
});
|
||||
|
||||
it('should invoke the callback without error when 304', function (done) {
|
||||
var app = express();
|
||||
var cb = after(3, done);
|
||||
|
||||
app.use(function (req, res) {
|
||||
res.sendfile('test/fixtures/name.txt', cb);
|
||||
});
|
||||
|
||||
request(app)
|
||||
.get('/')
|
||||
.expect('ETag', /^(?:W\/)?"[^"]+"$/)
|
||||
.expect(200, 'tobi', function (err, res) {
|
||||
if (err) return cb(err);
|
||||
var etag = res.headers.etag;
|
||||
request(app)
|
||||
.get('/')
|
||||
.set('If-None-Match', etag)
|
||||
.expect(304, cb);
|
||||
});
|
||||
});
|
||||
|
||||
it('should invoke the callback on 404', function(done){
|
||||
var app = express();
|
||||
var calls = 0;
|
||||
|
||||
app.use(function(req, res){
|
||||
res.sendfile('test/fixtures/nope.html', function(err){
|
||||
assert.equal(calls++, 0);
|
||||
assert(!res.headersSent);
|
||||
res.send(err.message);
|
||||
});
|
||||
});
|
||||
|
||||
request(app)
|
||||
.get('/')
|
||||
.expect(200, /^ENOENT.*?, stat/, done);
|
||||
})
|
||||
|
||||
it('should not override manual content-types', function(done){
|
||||
var app = express();
|
||||
|
||||
app.use(function(req, res){
|
||||
res.contentType('txt');
|
||||
res.sendfile('test/fixtures/user.html');
|
||||
});
|
||||
|
||||
request(app)
|
||||
.get('/')
|
||||
.expect('Content-Type', 'text/plain; charset=utf-8')
|
||||
.end(done);
|
||||
})
|
||||
|
||||
it('should invoke the callback on 403', function(done){
|
||||
var app = express()
|
||||
|
||||
app.use(function(req, res){
|
||||
res.sendfile('test/fixtures/foo/../user.html', function(err){
|
||||
assert(!res.headersSent);
|
||||
res.send(err.message);
|
||||
});
|
||||
});
|
||||
|
||||
request(app)
|
||||
.get('/')
|
||||
.expect('Forbidden')
|
||||
.expect(200, done);
|
||||
})
|
||||
|
||||
it('should invoke the callback on socket error', function(done){
|
||||
var app = express()
|
||||
|
||||
app.use(function(req, res){
|
||||
res.sendfile('test/fixtures/user.html', function(err){
|
||||
assert.ok(err)
|
||||
assert.ok(!res.headersSent)
|
||||
assert.strictEqual(err.message, 'broken!')
|
||||
done();
|
||||
});
|
||||
|
||||
req.socket.destroy(new Error('broken!'))
|
||||
});
|
||||
|
||||
request(app)
|
||||
.get('/')
|
||||
.end(function(){});
|
||||
})
|
||||
|
||||
describeAsyncHooks('async local storage', function () {
|
||||
it('should presist store', function (done) {
|
||||
var app = express()
|
||||
var cb = after(2, done)
|
||||
var store = { foo: 'bar' }
|
||||
|
||||
app.use(function (req, res, next) {
|
||||
req.asyncLocalStorage = new asyncHooks.AsyncLocalStorage()
|
||||
req.asyncLocalStorage.run(store, next)
|
||||
})
|
||||
|
||||
app.use(function (req, res) {
|
||||
res.sendfile('test/fixtures/name.txt', function (err) {
|
||||
if (err) return cb(err)
|
||||
|
||||
var local = req.asyncLocalStorage.getStore()
|
||||
|
||||
assert.strictEqual(local.foo, 'bar')
|
||||
cb()
|
||||
})
|
||||
})
|
||||
|
||||
request(app)
|
||||
.get('/')
|
||||
.expect('Content-Type', 'text/plain; charset=UTF-8')
|
||||
.expect(200, 'tobi', cb)
|
||||
})
|
||||
|
||||
it('should presist store on error', function (done) {
|
||||
var app = express()
|
||||
var store = { foo: 'bar' }
|
||||
|
||||
app.use(function (req, res, next) {
|
||||
req.asyncLocalStorage = new asyncHooks.AsyncLocalStorage()
|
||||
req.asyncLocalStorage.run(store, next)
|
||||
})
|
||||
|
||||
app.use(function (req, res) {
|
||||
res.sendfile('test/fixtures/does-not-exist', function (err) {
|
||||
var local = req.asyncLocalStorage.getStore()
|
||||
|
||||
if (local) {
|
||||
res.setHeader('x-store-foo', String(local.foo))
|
||||
}
|
||||
|
||||
res.send(err ? 'got ' + err.status + ' error' : 'no error')
|
||||
})
|
||||
})
|
||||
|
||||
request(app)
|
||||
.get('/')
|
||||
.expect(200)
|
||||
.expect('x-store-foo', 'bar')
|
||||
.expect('got 404 error')
|
||||
.end(done)
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
describe('.sendfile(path)', function(){
|
||||
it('should not serve dotfiles', function(done){
|
||||
var app = express();
|
||||
|
||||
app.use(function(req, res){
|
||||
res.sendfile('test/fixtures/.name');
|
||||
});
|
||||
|
||||
request(app)
|
||||
.get('/')
|
||||
.expect(404, done);
|
||||
})
|
||||
|
||||
it('should accept dotfiles option', function(done){
|
||||
var app = express();
|
||||
|
||||
app.use(function(req, res){
|
||||
res.sendfile('test/fixtures/.name', { dotfiles: 'allow' });
|
||||
});
|
||||
|
||||
request(app)
|
||||
.get('/')
|
||||
.expect(200)
|
||||
.expect(utils.shouldHaveBody(Buffer.from('tobi')))
|
||||
.end(done)
|
||||
})
|
||||
|
||||
it('should accept headers option', function(done){
|
||||
var app = express();
|
||||
var headers = {
|
||||
'x-success': 'sent',
|
||||
'x-other': 'done'
|
||||
};
|
||||
|
||||
app.use(function(req, res){
|
||||
res.sendfile('test/fixtures/user.html', { headers: headers });
|
||||
});
|
||||
|
||||
request(app)
|
||||
.get('/')
|
||||
.expect('x-success', 'sent')
|
||||
.expect('x-other', 'done')
|
||||
.expect(200, done);
|
||||
})
|
||||
|
||||
it('should ignore headers option on 404', function(done){
|
||||
var app = express();
|
||||
var headers = { 'x-success': 'sent' };
|
||||
|
||||
app.use(function(req, res){
|
||||
res.sendfile('test/fixtures/user.nothing', { headers: headers });
|
||||
});
|
||||
|
||||
request(app)
|
||||
.get('/')
|
||||
.expect(utils.shouldNotHaveHeader('X-Success'))
|
||||
.expect(404, done);
|
||||
})
|
||||
|
||||
it('should transfer a file', function (done) {
|
||||
var app = express();
|
||||
|
||||
app.use(function (req, res) {
|
||||
res.sendfile('test/fixtures/name.txt');
|
||||
});
|
||||
|
||||
request(app)
|
||||
.get('/')
|
||||
.expect(200, 'tobi', done);
|
||||
});
|
||||
|
||||
it('should transfer a directory index file', function (done) {
|
||||
var app = express();
|
||||
|
||||
app.use(function (req, res) {
|
||||
res.sendfile('test/fixtures/blog/');
|
||||
});
|
||||
|
||||
request(app)
|
||||
.get('/')
|
||||
.expect(200, '<b>index</b>', done);
|
||||
});
|
||||
|
||||
it('should 404 for directory without trailing slash', function (done) {
|
||||
var app = express();
|
||||
|
||||
app.use(function (req, res) {
|
||||
res.sendfile('test/fixtures/blog');
|
||||
});
|
||||
|
||||
request(app)
|
||||
.get('/')
|
||||
.expect(404, done);
|
||||
});
|
||||
|
||||
it('should transfer a file with urlencoded name', function (done) {
|
||||
var app = express();
|
||||
|
||||
app.use(function (req, res) {
|
||||
res.sendfile('test/fixtures/%25%20of%20dogs.txt');
|
||||
});
|
||||
|
||||
request(app)
|
||||
.get('/')
|
||||
.expect(200, '20%', done);
|
||||
});
|
||||
|
||||
it('should not error if the client aborts', function (done) {
|
||||
var app = express();
|
||||
var cb = after(2, done)
|
||||
var error = null
|
||||
|
||||
app.use(function (req, res) {
|
||||
setImmediate(function () {
|
||||
res.sendfile(path.resolve(fixtures, 'name.txt'));
|
||||
setTimeout(function () {
|
||||
cb(error)
|
||||
}, 10)
|
||||
});
|
||||
test.req.abort()
|
||||
});
|
||||
|
||||
app.use(function (err, req, res, next) {
|
||||
error = err
|
||||
next(err)
|
||||
});
|
||||
|
||||
var server = app.listen()
|
||||
var test = request(server).get('/')
|
||||
test.end(function (err) {
|
||||
assert.ok(err)
|
||||
server.close(cb)
|
||||
})
|
||||
})
|
||||
|
||||
describe('with an absolute path', function(){
|
||||
it('should transfer the file', function(done){
|
||||
var app = express();
|
||||
|
||||
app.use(function(req, res){
|
||||
res.sendfile(path.join(__dirname, '/fixtures/user.html'))
|
||||
});
|
||||
|
||||
request(app)
|
||||
.get('/')
|
||||
.expect('Content-Type', 'text/html; charset=UTF-8')
|
||||
.expect(200, '<p>{{user.name}}</p>', done);
|
||||
})
|
||||
})
|
||||
|
||||
describe('with a relative path', function(){
|
||||
it('should transfer the file', function(done){
|
||||
var app = express();
|
||||
|
||||
app.use(function(req, res){
|
||||
res.sendfile('test/fixtures/user.html');
|
||||
});
|
||||
|
||||
request(app)
|
||||
.get('/')
|
||||
.expect('Content-Type', 'text/html; charset=UTF-8')
|
||||
.expect(200, '<p>{{user.name}}</p>', done);
|
||||
})
|
||||
|
||||
it('should serve relative to "root"', function(done){
|
||||
var app = express();
|
||||
|
||||
app.use(function(req, res){
|
||||
res.sendfile('user.html', { root: 'test/fixtures/' });
|
||||
});
|
||||
|
||||
request(app)
|
||||
.get('/')
|
||||
.expect('Content-Type', 'text/html; charset=UTF-8')
|
||||
.expect(200, '<p>{{user.name}}</p>', done);
|
||||
})
|
||||
|
||||
it('should consider ../ malicious when "root" is not set', function(done){
|
||||
var app = express();
|
||||
|
||||
app.use(function(req, res){
|
||||
res.sendfile('test/fixtures/foo/../user.html');
|
||||
});
|
||||
|
||||
request(app)
|
||||
.get('/')
|
||||
.expect(403, done);
|
||||
})
|
||||
|
||||
it('should allow ../ when "root" is set', function(done){
|
||||
var app = express();
|
||||
|
||||
app.use(function(req, res){
|
||||
res.sendfile('foo/../user.html', { root: 'test/fixtures' });
|
||||
});
|
||||
|
||||
request(app)
|
||||
.get('/')
|
||||
.expect(200, done);
|
||||
})
|
||||
|
||||
it('should disallow requesting out of "root"', function(done){
|
||||
var app = express();
|
||||
|
||||
app.use(function(req, res){
|
||||
res.sendfile('foo/../../user.html', { root: 'test/fixtures' });
|
||||
});
|
||||
|
||||
request(app)
|
||||
.get('/')
|
||||
.expect(403, done);
|
||||
})
|
||||
|
||||
it('should next(404) when not found', function(done){
|
||||
var app = express()
|
||||
, calls = 0;
|
||||
|
||||
app.use(function(req, res){
|
||||
res.sendfile('user.html');
|
||||
});
|
||||
|
||||
app.use(function(req, res){
|
||||
assert(0, 'this should not be called');
|
||||
});
|
||||
|
||||
app.use(function(err, req, res, next){
|
||||
++calls;
|
||||
next(err);
|
||||
});
|
||||
|
||||
request(app)
|
||||
.get('/')
|
||||
.expect(404, function (err) {
|
||||
if (err) return done(err)
|
||||
assert.strictEqual(calls, 1)
|
||||
done()
|
||||
})
|
||||
})
|
||||
|
||||
describe('with non-GET', function(){
|
||||
it('should still serve', function(done){
|
||||
var app = express()
|
||||
|
||||
app.use(function(req, res){
|
||||
res.sendfile(path.join(__dirname, '/fixtures/name.txt'))
|
||||
});
|
||||
|
||||
request(app)
|
||||
.get('/')
|
||||
.expect('tobi', done);
|
||||
})
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
describe('.sendfile(path, options)', function () {
|
||||
it('should pass options to send module', function (done) {
|
||||
var app = express()
|
||||
|
||||
app.use(function (req, res) {
|
||||
res.sendfile(path.resolve(fixtures, 'name.txt'), { start: 0, end: 1 })
|
||||
})
|
||||
|
||||
request(app)
|
||||
.get('/')
|
||||
.expect(200, 'to', done)
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
function createApp(path, options, fn) {
|
||||
|
|
@ -1402,11 +910,3 @@ function createApp(path, options, fn) {
|
|||
|
||||
return app;
|
||||
}
|
||||
|
||||
function tryRequire (name) {
|
||||
try {
|
||||
return require(name)
|
||||
} catch (e) {
|
||||
return {}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -28,5 +28,17 @@ describe('res', function () {
|
|||
.get('/')
|
||||
.expect(599, '599', done);
|
||||
})
|
||||
|
||||
it('should raise error for invalid status code', function (done) {
|
||||
var app = express()
|
||||
|
||||
app.use(function (req, res) {
|
||||
res.sendStatus(undefined).end()
|
||||
})
|
||||
|
||||
request(app)
|
||||
.get('/')
|
||||
.expect(500, /TypeError: Invalid status code/, done)
|
||||
})
|
||||
})
|
||||
})
|
||||
|
|
|
|||
|
|
@ -1,55 +1,36 @@
|
|||
'use strict'
|
||||
|
||||
var express = require('../')
|
||||
var request = require('supertest')
|
||||
|
||||
var isIoJs = process.release
|
||||
? process.release.name === 'io.js'
|
||||
: ['v1.', 'v2.', 'v3.'].indexOf(process.version.slice(0, 3)) !== -1
|
||||
const express = require('../.');
|
||||
const request = require('supertest');
|
||||
|
||||
describe('res', function () {
|
||||
describe('.status(code)', function () {
|
||||
describe('when "code" is undefined', function () {
|
||||
it('should raise error for invalid status code', function (done) {
|
||||
|
||||
it('should set the status code when valid', function (done) {
|
||||
var app = express();
|
||||
|
||||
app.use(function (req, res) {
|
||||
res.status(200).end();
|
||||
});
|
||||
|
||||
request(app)
|
||||
.get('/')
|
||||
.expect(200, done);
|
||||
});
|
||||
|
||||
describe('accept valid ranges', function() {
|
||||
// not testing w/ 100, because that has specific meaning and behavior in Node as Expect: 100-continue
|
||||
it('should set the response status code to 101', function (done) {
|
||||
var app = express()
|
||||
|
||||
app.use(function (req, res) {
|
||||
res.status(undefined).end()
|
||||
res.status(101).end()
|
||||
})
|
||||
|
||||
request(app)
|
||||
.get('/')
|
||||
.expect(500, /Invalid status code/, function (err) {
|
||||
if (isIoJs) {
|
||||
done(err ? null : new Error('expected error'))
|
||||
} else {
|
||||
done(err)
|
||||
}
|
||||
})
|
||||
.expect(101, done)
|
||||
})
|
||||
})
|
||||
|
||||
describe('when "code" is null', function () {
|
||||
it('should raise error for invalid status code', function (done) {
|
||||
var app = express()
|
||||
|
||||
app.use(function (req, res) {
|
||||
res.status(null).end()
|
||||
})
|
||||
|
||||
request(app)
|
||||
.get('/')
|
||||
.expect(500, /Invalid status code/, function (err) {
|
||||
if (isIoJs) {
|
||||
done(err ? null : new Error('expected error'))
|
||||
} else {
|
||||
done(err)
|
||||
}
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
describe('when "code" is 201', function () {
|
||||
it('should set the response status code to 201', function (done) {
|
||||
var app = express()
|
||||
|
||||
|
|
@ -61,9 +42,7 @@ describe('res', function () {
|
|||
.get('/')
|
||||
.expect(201, done)
|
||||
})
|
||||
})
|
||||
|
||||
describe('when "code" is 302', function () {
|
||||
it('should set the response status code to 302', function (done) {
|
||||
var app = express()
|
||||
|
||||
|
|
@ -75,9 +54,7 @@ describe('res', function () {
|
|||
.get('/')
|
||||
.expect(302, done)
|
||||
})
|
||||
})
|
||||
|
||||
describe('when "code" is 403', function () {
|
||||
it('should set the response status code to 403', function (done) {
|
||||
var app = express()
|
||||
|
||||
|
|
@ -89,9 +66,7 @@ describe('res', function () {
|
|||
.get('/')
|
||||
.expect(403, done)
|
||||
})
|
||||
})
|
||||
|
||||
describe('when "code" is 501', function () {
|
||||
it('should set the response status code to 501', function (done) {
|
||||
var app = express()
|
||||
|
||||
|
|
@ -103,100 +78,129 @@ describe('res', function () {
|
|||
.get('/')
|
||||
.expect(501, done)
|
||||
})
|
||||
})
|
||||
|
||||
describe('when "code" is "410"', function () {
|
||||
it('should set the response status code to 410', function (done) {
|
||||
it('should set the response status code to 700', function (done) {
|
||||
var app = express()
|
||||
|
||||
app.use(function (req, res) {
|
||||
res.status('410').end()
|
||||
res.status(700).end()
|
||||
})
|
||||
|
||||
request(app)
|
||||
.get('/')
|
||||
.expect(410, done)
|
||||
.expect(700, done)
|
||||
})
|
||||
})
|
||||
|
||||
describe('when "code" is 410.1', function () {
|
||||
it('should set the response status code to 410', function (done) {
|
||||
it('should set the response status code to 800', function (done) {
|
||||
var app = express()
|
||||
|
||||
app.use(function (req, res) {
|
||||
res.status(410.1).end()
|
||||
res.status(800).end()
|
||||
})
|
||||
|
||||
request(app)
|
||||
.get('/')
|
||||
.expect(410, function (err) {
|
||||
if (isIoJs) {
|
||||
done(err ? null : new Error('expected error'))
|
||||
} else {
|
||||
done(err)
|
||||
}
|
||||
})
|
||||
.expect(800, done)
|
||||
})
|
||||
})
|
||||
|
||||
describe('when "code" is 1000', function () {
|
||||
it('should raise error for invalid status code', function (done) {
|
||||
it('should set the response status code to 900', function (done) {
|
||||
var app = express()
|
||||
|
||||
app.use(function (req, res) {
|
||||
res.status(1000).end()
|
||||
res.status(900).end()
|
||||
})
|
||||
|
||||
request(app)
|
||||
.get('/')
|
||||
.expect(500, /Invalid status code/, function (err) {
|
||||
if (isIoJs) {
|
||||
done(err ? null : new Error('expected error'))
|
||||
} else {
|
||||
done(err)
|
||||
}
|
||||
})
|
||||
.expect(900, done)
|
||||
})
|
||||
})
|
||||
|
||||
describe('when "code" is 99', function () {
|
||||
it('should raise error for invalid status code', function (done) {
|
||||
var app = express()
|
||||
describe('invalid status codes', function () {
|
||||
it('should raise error for status code below 100', function (done) {
|
||||
var app = express();
|
||||
|
||||
app.use(function (req, res) {
|
||||
res.status(99).end()
|
||||
})
|
||||
res.status(99).end();
|
||||
});
|
||||
|
||||
request(app)
|
||||
.get('/')
|
||||
.expect(500, /Invalid status code/, function (err) {
|
||||
if (isIoJs) {
|
||||
done(err ? null : new Error('expected error'))
|
||||
} else {
|
||||
done(err)
|
||||
}
|
||||
})
|
||||
})
|
||||
})
|
||||
.expect(500, /Invalid status code/, done);
|
||||
});
|
||||
|
||||
describe('when "code" is -401', function () {
|
||||
it('should raise error for invalid status code', function (done) {
|
||||
var app = express()
|
||||
it('should raise error for status code above 999', function (done) {
|
||||
var app = express();
|
||||
|
||||
app.use(function (req, res) {
|
||||
res.status(-401).end()
|
||||
})
|
||||
res.status(1000).end();
|
||||
});
|
||||
|
||||
request(app)
|
||||
.get('/')
|
||||
.expect(500, /Invalid status code/, function (err) {
|
||||
if (isIoJs) {
|
||||
done(err ? null : new Error('expected error'))
|
||||
} else {
|
||||
done(err)
|
||||
}
|
||||
})
|
||||
})
|
||||
})
|
||||
})
|
||||
})
|
||||
.expect(500, /Invalid status code/, done);
|
||||
});
|
||||
|
||||
it('should raise error for non-integer status codes', function (done) {
|
||||
var app = express();
|
||||
|
||||
app.use(function (req, res) {
|
||||
res.status(200.1).end();
|
||||
});
|
||||
|
||||
request(app)
|
||||
.get('/')
|
||||
.expect(500, /Invalid status code/, done);
|
||||
});
|
||||
|
||||
it('should raise error for undefined status code', function (done) {
|
||||
var app = express();
|
||||
|
||||
app.use(function (req, res) {
|
||||
res.status(undefined).end();
|
||||
});
|
||||
|
||||
request(app)
|
||||
.get('/')
|
||||
.expect(500, /Invalid status code/, done);
|
||||
});
|
||||
|
||||
it('should raise error for null status code', function (done) {
|
||||
var app = express();
|
||||
|
||||
app.use(function (req, res) {
|
||||
res.status(null).end();
|
||||
});
|
||||
|
||||
request(app)
|
||||
.get('/')
|
||||
.expect(500, /Invalid status code/, done);
|
||||
});
|
||||
|
||||
it('should raise error for string status code', function (done) {
|
||||
var app = express();
|
||||
|
||||
app.use(function (req, res) {
|
||||
res.status("200").end();
|
||||
});
|
||||
|
||||
request(app)
|
||||
.get('/')
|
||||
.expect(500, /Invalid status code/, done);
|
||||
});
|
||||
|
||||
it('should raise error for NaN status code', function (done) {
|
||||
var app = express();
|
||||
|
||||
app.use(function (req, res) {
|
||||
res.status(NaN).end();
|
||||
});
|
||||
|
||||
request(app)
|
||||
.get('/')
|
||||
.expect(500, /Invalid status code/, done);
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
|
|
|
|||
|
|
@ -14,7 +14,7 @@ describe('res', function(){
|
|||
|
||||
request(app)
|
||||
.get('/')
|
||||
.expect('Content-Type', 'application/javascript; charset=utf-8')
|
||||
.expect('Content-Type', 'text/javascript; charset=utf-8')
|
||||
.end(done)
|
||||
})
|
||||
|
||||
|
|
|
|||
|
|
@ -6,7 +6,7 @@ var utils = require('./support/utils');
|
|||
|
||||
describe('res.vary()', function(){
|
||||
describe('with no arguments', function(){
|
||||
it('should not set Vary', function (done) {
|
||||
it('should throw error', function (done) {
|
||||
var app = express();
|
||||
|
||||
app.use(function (req, res) {
|
||||
|
|
@ -16,8 +16,7 @@ describe('res.vary()', function(){
|
|||
|
||||
request(app)
|
||||
.get('/')
|
||||
.expect(utils.shouldNotHaveHeader('Vary'))
|
||||
.expect(200, done);
|
||||
.expect(500, /field.*required/, done)
|
||||
})
|
||||
})
|
||||
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
var fs = require('fs');
|
||||
var fs = require('node:fs');
|
||||
|
||||
var variableRegExp = /\$([0-9a-zA-Z\.]+)/g;
|
||||
|
||||
|
|
|
|||
|
|
@ -4,8 +4,7 @@
|
|||
* @private
|
||||
*/
|
||||
|
||||
var assert = require('assert');
|
||||
var Buffer = require('safe-buffer').Buffer
|
||||
var assert = require('node:assert');
|
||||
|
||||
/**
|
||||
* Module exports.
|
||||
|
|
|
|||
|
|
@ -1,7 +1,6 @@
|
|||
'use strict'
|
||||
|
||||
var assert = require('assert');
|
||||
var Buffer = require('safe-buffer').Buffer
|
||||
var assert = require('node:assert');
|
||||
var utils = require('../lib/utils');
|
||||
|
||||
describe('utils.etag(body, encoding)', function(){
|
||||
|
|
@ -69,35 +68,3 @@ describe('utils.wetag(body, encoding)', function(){
|
|||
'W/"0-2jmj7l5rSw0yVb/vlWAYkK/YBwk"')
|
||||
})
|
||||
})
|
||||
|
||||
describe('utils.isAbsolute()', function(){
|
||||
it('should support windows', function(){
|
||||
assert(utils.isAbsolute('c:\\'));
|
||||
assert(utils.isAbsolute('c:/'));
|
||||
assert(!utils.isAbsolute(':\\'));
|
||||
})
|
||||
|
||||
it('should support windows unc', function(){
|
||||
assert(utils.isAbsolute('\\\\foo\\bar'))
|
||||
})
|
||||
|
||||
it('should support unices', function(){
|
||||
assert(utils.isAbsolute('/foo/bar'));
|
||||
assert(!utils.isAbsolute('foo/bar'));
|
||||
})
|
||||
})
|
||||
|
||||
describe('utils.flatten(arr)', function(){
|
||||
it('should flatten an array', function(){
|
||||
var arr = ['one', ['two', ['three', 'four'], 'five']];
|
||||
var flat = utils.flatten(arr)
|
||||
|
||||
assert.strictEqual(flat.length, 5)
|
||||
assert.strictEqual(flat[0], 'one')
|
||||
assert.strictEqual(flat[1], 'two')
|
||||
assert.strictEqual(flat[2], 'three')
|
||||
assert.strictEqual(flat[3], 'four')
|
||||
assert.strictEqual(flat[4], 'five')
|
||||
assert.ok(flat.every(function (v) { return typeof v === 'string' }))
|
||||
})
|
||||
})
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user