mirror of
https://github.com/zebrajr/express.git
synced 2026-01-15 12:15:27 +00:00
Merge tag '4.17.2'
This commit is contained in:
@@ -3,6 +3,6 @@ root: true
|
||||
rules:
|
||||
eol-last: error
|
||||
eqeqeq: [error, allow-null]
|
||||
indent: [error, 2, { SwitchCase: 1 }]
|
||||
indent: [error, 2, { MemberExpression: "off", SwitchCase: 1 }]
|
||||
no-trailing-spaces: error
|
||||
no-unused-vars: [error, { vars: all, args: none, ignoreRestSiblings: true }]
|
||||
|
||||
160
.github/workflows/ci.yml
vendored
Normal file
160
.github/workflows/ci.yml
vendored
Normal file
@@ -0,0 +1,160 @@
|
||||
name: ci
|
||||
|
||||
on:
|
||||
- pull_request
|
||||
- push
|
||||
|
||||
jobs:
|
||||
test:
|
||||
runs-on: ubuntu-latest
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
name:
|
||||
- Node.js 0.10
|
||||
- Node.js 0.12
|
||||
- io.js 1.x
|
||||
- io.js 2.x
|
||||
- io.js 3.x
|
||||
- Node.js 4.x
|
||||
- Node.js 5.x
|
||||
- Node.js 6.x
|
||||
- Node.js 7.x
|
||||
- Node.js 8.x
|
||||
- Node.js 9.x
|
||||
- Node.js 10.x
|
||||
- Node.js 11.x
|
||||
- Node.js 12.x
|
||||
- Node.js 13.x
|
||||
- Node.js 14.x
|
||||
|
||||
include:
|
||||
- name: Node.js 0.10
|
||||
node-version: "0.10"
|
||||
npm-i: mocha@3.5.3 supertest@2.0.0
|
||||
|
||||
- name: Node.js 0.12
|
||||
node-version: "0.12"
|
||||
npm-i: mocha@3.5.3 supertest@2.0.0
|
||||
|
||||
- name: io.js 1.x
|
||||
node-version: "1.8"
|
||||
npm-i: mocha@3.5.3 supertest@2.0.0
|
||||
|
||||
- name: io.js 2.x
|
||||
node-version: "2.5"
|
||||
npm-i: mocha@3.5.3 supertest@2.0.0
|
||||
|
||||
- name: io.js 3.x
|
||||
node-version: "3.3"
|
||||
npm-i: mocha@3.5.3 supertest@2.0.0
|
||||
|
||||
- name: Node.js 4.x
|
||||
node-version: "4.9"
|
||||
npm-i: mocha@5.2.0 supertest@3.4.2
|
||||
|
||||
- name: Node.js 5.x
|
||||
node-version: "5.12"
|
||||
npm-i: mocha@5.2.0 supertest@3.4.2
|
||||
|
||||
- name: Node.js 6.x
|
||||
node-version: "6.17"
|
||||
npm-i: mocha@6.2.2
|
||||
|
||||
- name: Node.js 7.x
|
||||
node-version: "7.10"
|
||||
npm-i: mocha@6.2.2
|
||||
|
||||
- name: Node.js 8.x
|
||||
node-version: "8.17"
|
||||
npm-i: mocha@7.2.0
|
||||
|
||||
- name: Node.js 9.x
|
||||
node-version: "9.11"
|
||||
npm-i: mocha@7.2.0
|
||||
|
||||
- name: Node.js 10.x
|
||||
node-version: "10.24"
|
||||
npm-i: mocha@8.4.0
|
||||
|
||||
- name: Node.js 11.x
|
||||
node-version: "11.15"
|
||||
npm-i: mocha@8.4.0
|
||||
|
||||
- name: Node.js 12.x
|
||||
node-version: "12.22"
|
||||
|
||||
- name: Node.js 13.x
|
||||
node-version: "13.14"
|
||||
|
||||
- name: Node.js 14.x
|
||||
node-version: "14.18"
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
|
||||
- name: Install Node.js ${{ 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: Setup Node.js version-specific dependencies
|
||||
shell: bash
|
||||
run: |
|
||||
# eslint for linting
|
||||
# - remove on Node.js < 10
|
||||
if [[ "$(cut -d. -f1 <<< "${{ matrix.node-version }}")" -lt 10 ]]; then
|
||||
node -pe 'Object.keys(require("./package").devDependencies).join("\n")' | \
|
||||
grep -E '^eslint(-|$)' | \
|
||||
sort -r | \
|
||||
xargs -n1 npm rm --silent --save-dev
|
||||
fi
|
||||
|
||||
- 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 ||:
|
||||
|
||||
- name: Run tests
|
||||
shell: bash
|
||||
run: npm run test-ci
|
||||
|
||||
- name: Lint code
|
||||
if: steps.list_env.outputs.eslint != ''
|
||||
run: npm run lint
|
||||
|
||||
- name: Collect code coverage
|
||||
uses: coverallsapp/github-action@master
|
||||
with:
|
||||
github-token: ${{ secrets.GITHUB_TOKEN }}
|
||||
flag-name: run-${{ matrix.test_number }}
|
||||
parallel: true
|
||||
|
||||
coverage:
|
||||
needs: test
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Upload code coverage
|
||||
uses: coverallsapp/github-action@master
|
||||
with:
|
||||
github-token: ${{ secrets.github_token }}
|
||||
parallel-finished: true
|
||||
66
.travis.yml
66
.travis.yml
@@ -1,66 +0,0 @@
|
||||
language: node_js
|
||||
node_js:
|
||||
- "0.10"
|
||||
- "0.12"
|
||||
- "1.8"
|
||||
- "2.5"
|
||||
- "3.3"
|
||||
- "4.9"
|
||||
- "5.12"
|
||||
- "6.17"
|
||||
- "7.10"
|
||||
- "8.16"
|
||||
- "9.11"
|
||||
- "10.15"
|
||||
- "11.15"
|
||||
- "12.3"
|
||||
matrix:
|
||||
include:
|
||||
- node_js: "13"
|
||||
env: "NVM_NODEJS_ORG_MIRROR=https://nodejs.org/download/nightly"
|
||||
allow_failures:
|
||||
# Allow the nightly installs to fail
|
||||
- env: "NVM_NODEJS_ORG_MIRROR=https://nodejs.org/download/nightly"
|
||||
sudo: false
|
||||
cache:
|
||||
directories:
|
||||
- node_modules
|
||||
before_install:
|
||||
# Configure npm
|
||||
- |
|
||||
# Skip updating shrinkwrap / lock
|
||||
npm config set shrinkwrap false
|
||||
# Remove all non-test dependencies
|
||||
- |
|
||||
# Remove example dependencies
|
||||
npm rm --silent --save-dev connect-redis
|
||||
# Setup Node.js version-specific dependencies
|
||||
- |
|
||||
# mocha for testing
|
||||
# - use 3.x for Node.js < 6
|
||||
if [[ "$(cut -d. -f1 <<< "$TRAVIS_NODE_VERSION")" -lt 6 ]]; then
|
||||
npm install --silent --save-dev mocha@3.5.3
|
||||
fi
|
||||
- |
|
||||
# supertest for http calls
|
||||
# - use 2.0.0 for Node.js < 4
|
||||
if [[ "$(cut -d. -f1 <<< "$TRAVIS_NODE_VERSION")" -lt 4 ]]; then
|
||||
npm install --silent --save-dev supertest@2.0.0
|
||||
fi
|
||||
# Update Node.js modules
|
||||
- |
|
||||
# Prune and rebuild node_modules
|
||||
if [[ -d node_modules ]]; then
|
||||
npm prune
|
||||
npm rebuild
|
||||
fi
|
||||
script:
|
||||
# Run test script
|
||||
- npm run test-ci
|
||||
# Run linting
|
||||
- npm run lint
|
||||
after_script:
|
||||
- |
|
||||
# Upload coverage to coveralls
|
||||
npm install --save-dev coveralls@2.12.0
|
||||
coveralls < ./coverage/lcov.info
|
||||
92
Charter.md
Normal file
92
Charter.md
Normal file
@@ -0,0 +1,92 @@
|
||||
# Express Charter
|
||||
|
||||
## Section 0: Guiding Principles
|
||||
|
||||
The Express project is part of the OpenJS Foundation which operates
|
||||
transparently, openly, collaboratively, and ethically.
|
||||
Project proposals, timelines, and status must not merely be open, but
|
||||
also easily visible to outsiders.
|
||||
|
||||
## Section 1: Scope
|
||||
|
||||
Express is a http web server framework with a simple and expressive API
|
||||
which is highly aligned with Node.js core. We aim to be the best in
|
||||
class for writing performant, spec compliant, and powerful web servers
|
||||
in Node.js. As one of the oldest and most popular web frameworks in
|
||||
the ecosystem, we have an important place for new users and experts
|
||||
alike.
|
||||
|
||||
### 1.1: In-scope
|
||||
|
||||
Express is made of many modules spread between three GitHub Orgs:
|
||||
|
||||
- [expressjs](http://github.com/expressjs/): Top level middleware and
|
||||
libraries
|
||||
- [pillarjs](http://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
|
||||
|
||||
### 1.2: Out-of-Scope
|
||||
|
||||
Section Intentionally Left Blank
|
||||
|
||||
## Section 2: Relationship with OpenJS Foundation CPC.
|
||||
|
||||
Technical leadership for the projects within the OpenJS Foundation is
|
||||
delegated to the projects through their project charters by the OpenJS
|
||||
Cross Project Council (CPC). In the case of the Express project, it is
|
||||
delegated to the Express Technical Committee ("TC").
|
||||
|
||||
This Technical Committee is in charge of both the day-to-day operations
|
||||
of the project, as well as its technical management. This charter can
|
||||
be amended by the TC requiring at least two approvals and a minimum two
|
||||
week comment period for other TC members or CPC members to object. Any
|
||||
changes the CPC wishes to propose will be considered a priority but
|
||||
will follow the same process.
|
||||
|
||||
### 2.1 Other Formal Project Relationships
|
||||
|
||||
Section Intentionally Left Blank
|
||||
|
||||
## Section 3: Express Governing Body
|
||||
|
||||
The Express project is managed by the Technical Committee ("TC").
|
||||
Members can be added to the TC at any time. Any committer can nominate
|
||||
another committer to the TC and the TC uses its standard consensus
|
||||
seeking process to evaluate whether or not to add this new member.
|
||||
Members who do not participate consistently at the level of a majority
|
||||
of the other members are expected to resign.
|
||||
|
||||
## Section 4: Roles & Responsibilities
|
||||
|
||||
The Express TC manages all aspects of both the technical and community
|
||||
parts of the project. Members of the TC should attend the regular
|
||||
meetings when possible, and be available for discussion of time
|
||||
sensitive or important issues.
|
||||
|
||||
### Section 4.1 Project Operations & Management
|
||||
|
||||
Section Intentionally Left Blank
|
||||
|
||||
### Section 4.2: Decision-making, Voting, and/or Elections
|
||||
|
||||
The Express TC uses a "consensus seeking" process for issues that are
|
||||
escalated to the TC. The group tries to find a resolution that has no
|
||||
open objections among TC members. If a consensus cannot be reached
|
||||
that has no objections then a majority wins vote is called. It is also
|
||||
expected that the majority of decisions made by the TC are via a
|
||||
consensus seeking process and that voting is only used as a last-resort.
|
||||
|
||||
Resolution may involve returning the issue to committers with
|
||||
suggestions on how to move forward towards a consensus. It is not
|
||||
expected that a meeting of the TC will resolve all issues on its
|
||||
agenda during that meeting and may prefer to continue the discussion
|
||||
happening among the committers.
|
||||
|
||||
### Section 4.3: Other Project Roles
|
||||
|
||||
Section Intentionally Left Blank
|
||||
|
||||
## Section 5: Definitions
|
||||
|
||||
Section Intentionally Left Blank
|
||||
139
Code-Of-Conduct.md
Normal file
139
Code-Of-Conduct.md
Normal file
@@ -0,0 +1,139 @@
|
||||
# Contributor Covenant Code of Conduct
|
||||
|
||||
As a member of the Open JS Foundation, Express has adopted the
|
||||
[Contributor Covenant 2.0][cc-20-doc].
|
||||
|
||||
If an issue arises and you cannot resolve it directly with the parties
|
||||
involved, you can report it to the Express project TC through the following
|
||||
email: express-coc@lists.openjsf.org
|
||||
|
||||
In addition, the OpenJS Foundation maintains a Code of Conduct Panel (CoCP).
|
||||
This is a foundation-wide team established to manage escalation when a reporter
|
||||
believes that a report to a member project or the CPC has not been properly
|
||||
handled. In order to escalate to the CoCP send an email to
|
||||
coc-escalation@lists.openjsf.org.
|
||||
|
||||
## Our Pledge
|
||||
|
||||
We as members, contributors, and leaders pledge to make participation in our
|
||||
community a harassment-free experience for everyone, regardless of age, body
|
||||
size, visible or invisible disability, ethnicity, sex characteristics, gender
|
||||
identity and expression, level of experience, education, socio-economic status,
|
||||
nationality, personal appearance, race, religion, or sexual identity and
|
||||
orientation.
|
||||
|
||||
We pledge to act and interact in ways that contribute to an open, welcoming,
|
||||
diverse, inclusive, and healthy community.
|
||||
|
||||
## Our Standards
|
||||
|
||||
Examples of behavior that contributes to a positive environment for our
|
||||
community include:
|
||||
|
||||
* Demonstrating empathy and kindness toward other people
|
||||
* Being respectful of differing opinions, viewpoints, and experiences
|
||||
* Giving and gracefully accepting constructive feedback
|
||||
* Accepting responsibility and apologizing to those affected by our mistakes,
|
||||
and learning from the experience
|
||||
* Focusing on what is best not just for us as individuals, but for the overall
|
||||
community
|
||||
|
||||
Examples of unacceptable behavior include:
|
||||
|
||||
* The use of sexualized language or imagery, and sexual attention or advances
|
||||
of any kind
|
||||
* Trolling, insulting or derogatory comments, and personal or political attacks
|
||||
* Public or private harassment
|
||||
* Publishing others' private information, such as a physical or email address,
|
||||
without their explicit permission
|
||||
* Other conduct which could reasonably be considered inappropriate in a
|
||||
professional setting
|
||||
|
||||
## Enforcement Responsibilities
|
||||
|
||||
Community leaders are responsible for clarifying and enforcing our standards of
|
||||
acceptable behavior and will take appropriate and fair corrective action in
|
||||
response to any behavior that they deem inappropriate, threatening, offensive,
|
||||
or harmful.
|
||||
|
||||
Community leaders have the right and responsibility to remove, edit, or reject
|
||||
comments, commits, code, wiki edits, issues, and other contributions that are
|
||||
not aligned to this Code of Conduct, and will communicate reasons for
|
||||
moderation decisions when appropriate.
|
||||
|
||||
## Scope
|
||||
|
||||
This Code of Conduct applies within all community spaces, and also applies when
|
||||
an individual is officially representing the community in public spaces.
|
||||
Examples of representing our community include using an official e-mail
|
||||
address, posting via an official social media account, or acting as an
|
||||
appointed representative at an online or offline event.
|
||||
|
||||
## Enforcement
|
||||
|
||||
Instances of abusive, harassing, or otherwise unacceptable behavior may be
|
||||
reported to the community leaders responsible for enforcement at
|
||||
express-coc@lists.openjsf.org. All complaints will be reviewed and
|
||||
investigated promptly and fairly.
|
||||
|
||||
All community leaders are obligated to respect the privacy and security of the
|
||||
reporter of any incident.
|
||||
|
||||
## Enforcement Guidelines
|
||||
|
||||
Community leaders will follow these Community Impact Guidelines in determining
|
||||
the consequences for any action they deem in violation of this Code of Conduct:
|
||||
|
||||
### 1. Correction
|
||||
|
||||
**Community Impact**: Use of inappropriate language or other behavior deemed
|
||||
unprofessional or unwelcome in the community.
|
||||
|
||||
**Consequence**: A private, written warning from community leaders, providing
|
||||
clarity around the nature of the violation and an explanation of why the
|
||||
behavior was inappropriate. A public apology may be requested.
|
||||
|
||||
### 2. Warning
|
||||
|
||||
**Community Impact**: A violation through a single incident or series of
|
||||
actions.
|
||||
|
||||
**Consequence**: A warning with consequences for continued behavior. No
|
||||
interaction with the people involved, including unsolicited interaction with
|
||||
those enforcing the Code of Conduct, for a specified period of time. This
|
||||
includes avoiding interactions in community spaces as well as external channels
|
||||
like social media. Violating these terms may lead to a temporary or permanent
|
||||
ban.
|
||||
|
||||
### 3. Temporary Ban
|
||||
|
||||
**Community Impact**: A serious violation of community standards, including
|
||||
sustained inappropriate behavior.
|
||||
|
||||
**Consequence**: A temporary ban from any sort of interaction or public
|
||||
communication with the community for a specified period of time. No public or
|
||||
private interaction with the people involved, including unsolicited
|
||||
interaction with those enforcing the Code of Conduct, is allowed during this
|
||||
period. Violating these terms may lead to a permanent ban.
|
||||
|
||||
### 4. Permanent Ban
|
||||
|
||||
**Community Impact**: Demonstrating a pattern of violation of community
|
||||
standards, including sustained inappropriate behavior, harassment of an
|
||||
individual, or aggression toward or disparagement of classes of individuals.
|
||||
|
||||
**Consequence**: A permanent ban from any sort of public interaction within the
|
||||
project community.
|
||||
|
||||
## Attribution
|
||||
|
||||
This Code of Conduct is adapted from the [Contributor Covenant, version 2.0](cc-20-doc).
|
||||
|
||||
Community Impact Guidelines were inspired by
|
||||
[Mozilla's code of conduct enforcement ladder](https://github.com/mozilla/diversity).
|
||||
|
||||
[cc-20-doc]: https://www.contributor-covenant.org/version/2/0/code_of_conduct/
|
||||
|
||||
For answers to common questions about this code of conduct, see the FAQ at
|
||||
https://www.contributor-covenant.org/faq. Translations are available at
|
||||
https://www.contributor-covenant.org/translations.
|
||||
@@ -1,3 +1,4 @@
|
||||
# Express Collaborator Guide
|
||||
|
||||
## Website Issues
|
||||
|
||||
@@ -21,7 +22,7 @@ a future release of Express.
|
||||
|
||||
1. [Create an issue](https://github.com/expressjs/express/issues/new) for the
|
||||
bug you want to fix or the feature that you want to add.
|
||||
2. Create your own [fork](https://github.com/expressjs/express) on github, then
|
||||
2. Create your own [fork](https://github.com/expressjs/express) on GitHub, then
|
||||
checkout your fork.
|
||||
3. Write your code in your local copy. It's good practice to create a branch for
|
||||
each new issue you work on, although not compulsory.
|
||||
|
||||
@@ -14,8 +14,9 @@ contributors can be involved in decision making.
|
||||
* A **Committer** is a subset of contributors who have been given write access to the repository.
|
||||
* A **TC (Technical Committee)** is a group of committers representing the required technical
|
||||
expertise to resolve rare disputes.
|
||||
* A **Triager** is a subset of contributors who have been given triage access to the repository.
|
||||
|
||||
# Logging Issues
|
||||
## Logging Issues
|
||||
|
||||
Log an issue for any question or problem you might have. When in doubt, log an issue, and
|
||||
any additional policies about what to include will be provided in the responses. The only
|
||||
@@ -27,7 +28,7 @@ add appropriate metadata before the issue is addressed.
|
||||
Please be courteous and respectful. Every participant is expected to follow the
|
||||
project's Code of Conduct.
|
||||
|
||||
# Contributions
|
||||
## Contributions
|
||||
|
||||
Any change to resources in this repository must be through pull requests. This applies to all changes
|
||||
to documentation, code, binary files, etc. Even long term committers and TC members must use
|
||||
@@ -41,7 +42,7 @@ weekends and other holiday periods to ensure active committers all have reasonab
|
||||
become involved in the discussion and review process if they wish.
|
||||
|
||||
The default for each contribution is that it is accepted once no committer has an objection.
|
||||
During review committers may also request that a specific contributor who is most versed in a
|
||||
During a review, committers may also request that a specific contributor who is most versed in a
|
||||
particular area gives a "LGTM" before the PR can be merged. There is no additional "sign off"
|
||||
process for contributions to land. Once all issues brought by committers are addressed it can
|
||||
be landed by any committer.
|
||||
@@ -56,7 +57,36 @@ discuss pending contributions in order to find a resolution. It is expected that
|
||||
small minority of issues be brought to the TC for resolution and that discussion and
|
||||
compromise among committers be the default resolution mechanism.
|
||||
|
||||
# Becoming a Committer
|
||||
## Becoming a Triager
|
||||
|
||||
Anyone can become a triager! Read more about the process of being a triager in
|
||||
[the triage process document](Triager-Guide.md).
|
||||
|
||||
[Open an issue in `expressjs/express` repo](https://github.com/expressjs/express/issues/new)
|
||||
to request the triage role. State that you have read and agree to the
|
||||
[Code of Conduct](Code-Of-Conduct.md) and details of the role.
|
||||
|
||||
Here is an example issue content you can copy and paste:
|
||||
|
||||
```
|
||||
Title: Request triager role for <your GitHub username>
|
||||
|
||||
I have read and understood the project's Code of Conduct.
|
||||
I also have read and understood the process and best practices around Express triaging.
|
||||
|
||||
I request for a triager role for the following GitHub organizations:
|
||||
|
||||
jshttp
|
||||
pillarjs
|
||||
express
|
||||
```
|
||||
|
||||
Once you have opened your issue, a member of the TC will add you to the `triage` team in
|
||||
the organizations requested. They will then close the issue.
|
||||
|
||||
Happy triaging!
|
||||
|
||||
## Becoming a Committer
|
||||
|
||||
All contributors who land a non-trivial contribution should be on-boarded in a timely manner,
|
||||
and added as a committer, and be given write access to the repository.
|
||||
@@ -64,7 +94,7 @@ and added as a committer, and be given write access to the repository.
|
||||
Committers are expected to follow this policy and continue to send pull requests, go through
|
||||
proper review, and have other committers merge their pull requests.
|
||||
|
||||
# TC Process
|
||||
## TC Process
|
||||
|
||||
The TC uses a "consensus seeking" process for issues that are escalated to the TC.
|
||||
The group tries to find a resolution that has no open objections among TC members.
|
||||
@@ -81,5 +111,3 @@ Members can be added to the TC at any time. Any committer can nominate another c
|
||||
to the TC and the TC uses its standard consensus seeking process to evaluate whether or
|
||||
not to add this new member. Members who do not participate consistently at the level of
|
||||
a majority of the other members are expected to resign.
|
||||
|
||||
|
||||
|
||||
38
History.md
38
History.md
@@ -1,3 +1,8 @@
|
||||
5.x
|
||||
===
|
||||
|
||||
This incorporates all changes after 4.17.1 up to 4.17.2.
|
||||
|
||||
5.0.0-alpha.8 / 2020-03-25
|
||||
==========================
|
||||
|
||||
@@ -119,6 +124,39 @@ This is the first Express 5.0 alpha release, based off 4.10.1.
|
||||
* add:
|
||||
- `app.router` is a reference to the base router
|
||||
|
||||
4.17.2 / 2021-12-16
|
||||
===================
|
||||
|
||||
* Fix handling of `undefined` in `res.jsonp`
|
||||
* Fix handling of `undefined` when `"json escape"` is enabled
|
||||
* Fix incorrect middleware execution with unanchored `RegExp`s
|
||||
* Fix `res.jsonp(obj, status)` deprecation message
|
||||
* Fix typo in `res.is` JSDoc
|
||||
* deps: body-parser@1.19.1
|
||||
- deps: bytes@3.1.1
|
||||
- deps: http-errors@1.8.1
|
||||
- deps: qs@6.9.6
|
||||
- deps: raw-body@2.4.2
|
||||
- deps: safe-buffer@5.2.1
|
||||
- deps: type-is@~1.6.18
|
||||
* deps: content-disposition@0.5.4
|
||||
- deps: safe-buffer@5.2.1
|
||||
* deps: cookie@0.4.1
|
||||
- Fix `maxAge` option to reject invalid values
|
||||
* deps: proxy-addr@~2.0.7
|
||||
- Use `req.socket` over deprecated `req.connection`
|
||||
- deps: forwarded@0.2.0
|
||||
- deps: ipaddr.js@1.9.1
|
||||
* deps: qs@6.9.6
|
||||
* deps: safe-buffer@5.2.1
|
||||
* deps: send@0.17.2
|
||||
- deps: http-errors@1.8.1
|
||||
- deps: ms@2.1.3
|
||||
- pref: ignore empty http tokens
|
||||
* deps: serve-static@1.14.2
|
||||
- deps: send@0.17.2
|
||||
* deps: setprototypeof@1.2.0
|
||||
|
||||
4.17.1 / 2019-05-25
|
||||
===================
|
||||
|
||||
|
||||
13
Readme.md
13
Readme.md
@@ -4,7 +4,7 @@
|
||||
|
||||
[![NPM Version][npm-image]][npm-url]
|
||||
[![NPM Downloads][downloads-image]][downloads-url]
|
||||
[![Linux Build][travis-image]][travis-url]
|
||||
[![Linux Build][ci-image]][ci-url]
|
||||
[![Windows Build][appveyor-image]][appveyor-url]
|
||||
[![Test Coverage][coveralls-image]][coveralls-url]
|
||||
|
||||
@@ -27,6 +27,9 @@ This is a [Node.js](https://nodejs.org/en/) module available through the
|
||||
Before installing, [download and install Node.js](https://nodejs.org/en/download/).
|
||||
Node.js 0.10 or higher is required.
|
||||
|
||||
If this is a brand new project, make sure to create a `package.json` first with
|
||||
the [`npm init` command](https://docs.npmjs.com/creating-a-package-json-file).
|
||||
|
||||
Installation is done using the
|
||||
[`npm install` command](https://docs.npmjs.com/getting-started/installing-npm-packages-locally):
|
||||
|
||||
@@ -95,7 +98,7 @@ $ npm start
|
||||
## Philosophy
|
||||
|
||||
The Express philosophy is to provide small, robust tooling for HTTP servers, making
|
||||
it a great solution for single page applications, web sites, hybrids, or public
|
||||
it a great solution for single page applications, websites, hybrids, or public
|
||||
HTTP APIs.
|
||||
|
||||
Express does not force you to use any specific ORM or template engine. With support for over
|
||||
@@ -143,12 +146,12 @@ The current lead maintainer is [Douglas Christopher Wilson](https://github.com/d
|
||||
|
||||
[MIT](LICENSE)
|
||||
|
||||
[ci-image]: https://img.shields.io/github/workflow/status/expressjs/express/ci/master.svg?label=linux
|
||||
[ci-url]: https://github.com/expressjs/express/actions?query=workflow%3Aci
|
||||
[npm-image]: https://img.shields.io/npm/v/express.svg
|
||||
[npm-url]: https://npmjs.org/package/express
|
||||
[downloads-image]: https://img.shields.io/npm/dm/express.svg
|
||||
[downloads-url]: https://npmjs.org/package/express
|
||||
[travis-image]: https://img.shields.io/travis/expressjs/express/master.svg?label=linux
|
||||
[travis-url]: https://travis-ci.org/expressjs/express
|
||||
[downloads-url]: https://npmcharts.com/compare/express?minimal=true
|
||||
[appveyor-image]: https://img.shields.io/appveyor/ci/dougwilson/express/master.svg?label=windows
|
||||
[appveyor-url]: https://ci.appveyor.com/project/dougwilson/express
|
||||
[coveralls-image]: https://img.shields.io/coveralls/expressjs/express/master.svg
|
||||
|
||||
@@ -16,6 +16,10 @@ contributions.
|
||||
|
||||
Report security bugs by emailing the lead maintainer in the Readme.md file.
|
||||
|
||||
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
|
||||
link or an attachment.
|
||||
|
||||
The lead maintainer will acknowledge your email within 48 hours, and will send a
|
||||
more detailed response within 48 hours indicating the next steps in handling
|
||||
your report. After the initial reply to your report, the security team will
|
||||
|
||||
63
Triager-Guide.md
Normal file
63
Triager-Guide.md
Normal file
@@ -0,0 +1,63 @@
|
||||
# Express Triager Guide
|
||||
|
||||
## Issue Triage Process
|
||||
|
||||
When a new issue or pull request is opened the issue will be labeled with `needs triage`.
|
||||
If a triage team member is available they can help make sure all the required information
|
||||
is provided. Depending on the issue or PR there are several next labels they can add for further
|
||||
classification:
|
||||
|
||||
* `needs triage`: This can be kept if the triager is unsure which next steps to take
|
||||
* `awaiting more info`: If more info has been requested from the author, apply this label.
|
||||
* `question`: User questions that do not appear to be bugs or enhancements.
|
||||
* `discuss`: Topics for discussion. Might end in an `enhancement` or `question` label.
|
||||
* `bug`: Issues that present a reasonable conviction there is a reproducible bug.
|
||||
* `enhancement`: Issues that are found to be a reasonable candidate feature additions.
|
||||
|
||||
In all cases, issues may be closed by maintainers if they don't receive a timely response when
|
||||
further information is sought, or when additional questions are asked.
|
||||
|
||||
## Approaches and Best Practices for getting into triage contributions
|
||||
|
||||
Review the organization's [StatusBoard](https://expressjs.github.io/statusboard/),
|
||||
pay special attention to these columns: stars, watchers, open issues, and contributors.
|
||||
This gives you a general idea about the criticality and health of the repository.
|
||||
Pick a few projects based on that criteria, your interests, and skills (existing or aspiring).
|
||||
|
||||
Review the project's contribution guideline if present. In a nutshell,
|
||||
commit to the community's standards and values. Review the
|
||||
documentation, for most of the projects it is just the README.md, and
|
||||
make sure you understand the key APIs, semantics, configurations, and use cases.
|
||||
|
||||
It might be helpful to write your own test apps to re-affirm your
|
||||
understanding of the key functions. This may identify some gaps in
|
||||
documentation, record those as they might be good PR's to open.
|
||||
Skim through the issue backlog; identify low hanging issues and mostly new ones.
|
||||
From those, attempt to recreate issues based on the OP description and
|
||||
ask questions if required. No question is a bad question!
|
||||
|
||||
## Removal of Triage Role
|
||||
|
||||
There are a few cases where members can be removed as triagers:
|
||||
|
||||
- Breaking the CoC or project contributor guidelines
|
||||
- Abuse or misuse of the role as deemed by the TC
|
||||
- Lack of participation for more than 6 months
|
||||
|
||||
If any of these happen we will discuss as a part of the triage portion of the regular TC meetings.
|
||||
If you have questions feel free to reach out to any of the TC members.
|
||||
|
||||
## Other Helpful Hints:
|
||||
|
||||
- Everyone is welcome to attend the [Express Technical Committee Meetings](https://github.com/expressjs/discussions#expressjs-tc-meetings), and as a triager, it might help to get a better idea of what's happening with the project.
|
||||
- When exploring the module's functionality there are a few helpful steps:
|
||||
- Turn on `DEBUG=*` (see https://www.npmjs.com/package/debug) to get detailed log information
|
||||
- It is also a good idea to do live debugging to follow the control flow, try using `node --inspect`
|
||||
- It is a good idea to make at least one pass of reading through the entire source
|
||||
- When reviewing the list of open issues there are some common types and suggested actions:
|
||||
- New/unattended issues or simple questions: A good place to start
|
||||
- Hard bugs & ongoing discussions: always feel free to chime in and help
|
||||
- Issues that imply gaps in the documentation: open PRs with changes or help the user to do so
|
||||
- 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.
|
||||
37
appveyor.yml
37
appveyor.yml
@@ -9,11 +9,13 @@ environment:
|
||||
- nodejs_version: "5.12"
|
||||
- nodejs_version: "6.17"
|
||||
- nodejs_version: "7.10"
|
||||
- nodejs_version: "8.16"
|
||||
- nodejs_version: "8.17"
|
||||
- nodejs_version: "9.11"
|
||||
- nodejs_version: "10.15"
|
||||
- nodejs_version: "10.24"
|
||||
- nodejs_version: "11.15"
|
||||
- nodejs_version: "12.3"
|
||||
- nodejs_version: "12.22"
|
||||
- nodejs_version: "13.14"
|
||||
- nodejs_version: "14.18"
|
||||
cache:
|
||||
- node_modules
|
||||
install:
|
||||
@@ -23,24 +25,43 @@ install:
|
||||
catch { Update-NodeJsInstallation (Get-NodeJsLatestBuild $env:nodejs_version) }
|
||||
# Configure npm
|
||||
- ps: |
|
||||
# Skip updating shrinkwrap / lock
|
||||
npm config set loglevel error
|
||||
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 < 6
|
||||
if ($env:nodejs_version.split(".")[0] -lt 6) {
|
||||
# - 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
|
||||
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
|
||||
}
|
||||
- ps: |
|
||||
# supertest for http calls
|
||||
# - use 2.0.0 for Node.js < 4
|
||||
if ($env:nodejs_version.split(".")[0] -lt 4) {
|
||||
# - use 3.4.2 for Node.js < 6
|
||||
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 6) {
|
||||
npm install --silent --save-dev supertest@3.4.2
|
||||
}
|
||||
# Update Node.js modules
|
||||
- ps: |
|
||||
@@ -59,6 +80,4 @@ test_script:
|
||||
npm --version
|
||||
# Run test script
|
||||
- npm run test-ci
|
||||
# Run linting
|
||||
- npm run lint
|
||||
version: "{build}"
|
||||
|
||||
30
examples/README.md
Normal file
30
examples/README.md
Normal file
@@ -0,0 +1,30 @@
|
||||
# Express examples
|
||||
|
||||
This page contains list of examples using Express.
|
||||
|
||||
- [auth](./auth) - Authentication with login and password
|
||||
- [content-negotiation](./content-negotiation) - HTTP content negotiation
|
||||
- [cookie-sessions](./cookie-sessions) - Working with cookie-based sessions
|
||||
- [cookies](./cookies) - Working with cookies
|
||||
- [downloads](./downloads) - Transferring files to client
|
||||
- [ejs](./ejs) - Working with Embedded JavaScript templating (ejs)
|
||||
- [error-pages](./error-pages) - Creating error pages
|
||||
- [error](./error) - Working with error middleware
|
||||
- [hello-world](./hello-world) - Simple request handler
|
||||
- [markdown](./markdown) - Markdown as template engine
|
||||
- [multi-router](./multi-router) - Working with multiple Express routers
|
||||
- [multipart](./multipart) - Accepting multipart-encoded forms
|
||||
- [mvc](./mvc) - MVC-style controllers
|
||||
- [online](./online) - Tracking online user activity with `online` and `redis` packages
|
||||
- [params](./params) - Working with route parameters
|
||||
- [resource](./resource) - Multiple HTTP operations on the same resource
|
||||
- [route-map](./route-map) - Organizing routes using a map
|
||||
- [route-middleware](./route-middleware) - Working with route middleware
|
||||
- [route-separation](./route-separation) - Organizing routes per each resource
|
||||
- [search](./search) - Search API
|
||||
- [session](./session) - User sessions
|
||||
- [static-files](./static-files) - Serving static files
|
||||
- [vhost](./vhost) - Working with virtual hosts
|
||||
- [view-constructor](./view-constructor) - Rendering views dynamically
|
||||
- [view-locals](./view-locals) - Saving data in request object between middleware calls
|
||||
- [web-service](./web-service) - Simple API service
|
||||
@@ -1,6 +1,8 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta name="viewport" content="width=device-width,initial-scale=1">
|
||||
<title><%= title %></title>
|
||||
<style>
|
||||
body {
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
|
||||
<% var title = 'Authentication Example' %>
|
||||
<% include head %>
|
||||
<%- include('head', { title: 'Authentication Example' }) -%>
|
||||
|
||||
<h1>Login</h1>
|
||||
<%- message %>
|
||||
@@ -19,4 +18,4 @@ Try accessing <a href="/restricted">/restricted</a>, then authenticate with "tj"
|
||||
</p>
|
||||
</form>
|
||||
|
||||
<% include foot %>
|
||||
<%- include('foot') -%>
|
||||
|
||||
3
examples/downloads/files/notes/groceries.txt
Normal file
3
examples/downloads/files/notes/groceries.txt
Normal file
@@ -0,0 +1,3 @@
|
||||
* milk
|
||||
* eggs
|
||||
* bread
|
||||
@@ -7,11 +7,12 @@ var path = require('path');
|
||||
var app = module.exports = express();
|
||||
|
||||
app.get('/', function(req, res){
|
||||
res.send('<ul>'
|
||||
+ '<li>Download <a href="/files/amazing.txt">amazing.txt</a>.</li>'
|
||||
+ '<li>Download <a href="/files/missing.txt">missing.txt</a>.</li>'
|
||||
+ '<li>Download <a href="/files/CCTV大赛上海分赛区.txt">CCTV大赛上海分赛区.txt</a>.</li>'
|
||||
+ '</ul>');
|
||||
res.send('<ul>' +
|
||||
'<li>Download <a href="/files/notes/groceries.txt">notes/groceries.txt</a>.</li>' +
|
||||
'<li>Download <a href="/files/amazing.txt">amazing.txt</a>.</li>' +
|
||||
'<li>Download <a href="/files/missing.txt">missing.txt</a>.</li>' +
|
||||
'<li>Download <a href="/files/CCTV大赛上海分赛区.txt">CCTV大赛上海分赛区.txt</a>.</li>' +
|
||||
'</ul>')
|
||||
});
|
||||
|
||||
// /files/* is accessed via req.params[0]
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
body {
|
||||
padding: 50px 80px;
|
||||
font: 14px "Helvetica Nueue", "Lucida Grande", Arial, sans-serif;
|
||||
font: 14px "Helvetica Neue", "Lucida Grande", Arial, sans-serif;
|
||||
}
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta name="viewport" content="width=device-width,initial-scale=1">
|
||||
<title><%= title %></title>
|
||||
<link rel="stylesheet" href="/stylesheets/style.css">
|
||||
</head>
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
<% include header.html %>
|
||||
<%- include('header.html') -%>
|
||||
|
||||
<h1>Users</h1>
|
||||
<ul id="users">
|
||||
@@ -7,4 +7,4 @@
|
||||
<% }) %>
|
||||
</ul>
|
||||
|
||||
<% include footer.html %>
|
||||
<%- include('footer.html') -%>
|
||||
|
||||
@@ -1,3 +1,3 @@
|
||||
<% include error_header %>
|
||||
<%- include('error_header') -%>
|
||||
<h2>Cannot find <%= url %></h2>
|
||||
<% include footer %>
|
||||
<%- include('footer') -%>
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
<% include error_header %>
|
||||
<%- include('error_header') -%>
|
||||
<h2>Error: <%= error.message %></h2>
|
||||
<% if (settings['verbose errors']) { %>
|
||||
<pre><%= error.stack %></pre>
|
||||
<% } else { %>
|
||||
<p>An error occurred!</p>
|
||||
<% } %>
|
||||
<% include footer %>
|
||||
<%- include('footer') -%>
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta name="viewport" content="width=device-width,initial-scale=1">
|
||||
<title>Error</title>
|
||||
</head>
|
||||
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta name="viewport" content="width=device-width,initial-scale=1">
|
||||
<title>Custom Pages Example</title>
|
||||
</head>
|
||||
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta name="viewport" content="width=device-width,initial-scale=1">
|
||||
<link rel="stylesheet" href="/style.css">
|
||||
<title>Edit <%= pet.name %></title>
|
||||
</head>
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta name="viewport" content="width=device-width,initial-scale=1">
|
||||
<link rel="stylesheet" href="/style.css">
|
||||
<title><%= pet.name %></title>
|
||||
</head>
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta name="viewport" content="width=device-width,initial-scale=1">
|
||||
<link rel="stylesheet" href="/style.css">
|
||||
<title>Edit {{user.name}}</title>
|
||||
</head>
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta name="viewport" content="width=device-width,initial-scale=1">
|
||||
<link rel="stylesheet" href="/style.css">
|
||||
<title>Users</title>
|
||||
</head>
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta name="viewport" content="width=device-width,initial-scale=1">
|
||||
<link rel="stylesheet" href="/style.css">
|
||||
<title>{{user.name}}</title>
|
||||
</head>
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta name="viewport" content="width=device-width,initial-scale=1">
|
||||
<title>Not Found</title>
|
||||
<link rel="stylesheet" href="/style.css">
|
||||
</head>
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta name="viewport" content="width=device-width,initial-scale=1">
|
||||
<title>Internal Server Error</title>
|
||||
<link rel="stylesheet" href="/style.css">
|
||||
</head>
|
||||
|
||||
@@ -8,7 +8,7 @@ var app = module.exports = express();
|
||||
// Faux database
|
||||
|
||||
var users = [
|
||||
{ name: 'tj' }
|
||||
{ name: 'tj' }
|
||||
, { name: 'tobi' }
|
||||
, { name: 'loki' }
|
||||
, { name: 'jane' }
|
||||
|
||||
@@ -26,7 +26,7 @@ app.resource = function(path, obj) {
|
||||
// Fake records
|
||||
|
||||
var users = [
|
||||
{ name: 'tj' }
|
||||
{ name: 'tj' }
|
||||
, { name: 'ciaran' }
|
||||
, { name: 'aaron' }
|
||||
, { name: 'guillermo' }
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
* Module dependencies.
|
||||
*/
|
||||
|
||||
var escapeHtml = require('escape-html')
|
||||
var express = require('../../lib/express');
|
||||
|
||||
var verbose = process.env.NODE_ENV !== 'test'
|
||||
@@ -31,7 +32,7 @@ var users = {
|
||||
},
|
||||
|
||||
get: function(req, res){
|
||||
res.send('user ' + req.params.uid);
|
||||
res.send('user ' + escapeHtml(req.params.uid))
|
||||
},
|
||||
|
||||
delete: function(req, res){
|
||||
@@ -41,11 +42,11 @@ var users = {
|
||||
|
||||
var pets = {
|
||||
list: function(req, res){
|
||||
res.send('user ' + req.params.uid + '\'s pets');
|
||||
res.send('user ' + escapeHtml(req.params.uid) + '\'s pets')
|
||||
},
|
||||
|
||||
delete: function(req, res){
|
||||
res.send('delete ' + req.params.uid + '\'s pet ' + req.params.pid);
|
||||
res.send('delete ' + escapeHtml(req.params.uid) + '\'s pet ' + escapeHtml(req.params.pid))
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
@@ -15,7 +15,7 @@ var app = express();
|
||||
|
||||
// Dummy users
|
||||
var users = [
|
||||
{ id: 0, name: 'tj', email: 'tj@vision-media.ca', role: 'member' }
|
||||
{ id: 0, name: 'tj', email: 'tj@vision-media.ca', role: 'member' }
|
||||
, { id: 1, name: 'ciaran', email: 'ciaranj@gmail.com', role: 'member' }
|
||||
, { id: 2, name: 'aaron', email: 'aaron.heckmann+github@gmail.com', role: 'admin' }
|
||||
];
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta name="viewport" content="width=device-width,initial-scale=1">
|
||||
<title><%= title %></title>
|
||||
<link rel="stylesheet" href="/style.css">
|
||||
</head>
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
<% include header %>
|
||||
<%- include('header') -%>
|
||||
|
||||
<h1><%= title %></h1>
|
||||
|
||||
@@ -7,4 +7,4 @@
|
||||
<li>Visit the <a href="/posts">posts</a> page.</li>
|
||||
</ul>
|
||||
|
||||
<% include footer %>
|
||||
<%- include('footer') -%>
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
<% include ../header %>
|
||||
<%- include('../header') -%>
|
||||
|
||||
<h1>Posts</h1>
|
||||
|
||||
@@ -9,4 +9,4 @@
|
||||
<% }) %>
|
||||
</dl>
|
||||
|
||||
<% include ../footer %>
|
||||
<%- include('../footer') -%>
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
<% include ../header %>
|
||||
<%- include('../header') -%>
|
||||
|
||||
<h1>Editing <%= user.name %></h1>
|
||||
|
||||
@@ -20,4 +20,4 @@
|
||||
</form>
|
||||
</div>
|
||||
|
||||
<% include ../footer %>
|
||||
<%- include('../footer') -%>
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
<% include ../header %>
|
||||
<%- include('../header') -%>
|
||||
|
||||
<h1><%= title %></h1>
|
||||
|
||||
@@ -11,4 +11,4 @@
|
||||
<% }) %>
|
||||
</div>
|
||||
|
||||
<% include ../footer %>
|
||||
<%- include('../footer') -%>
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
<% include ../header %>
|
||||
<%- include('../header') -%>
|
||||
|
||||
<h1><%= user.name %></h1>
|
||||
|
||||
@@ -6,4 +6,4 @@
|
||||
<p>Email: <%= user.email %></p>
|
||||
</div>
|
||||
|
||||
<% include ../footer %>
|
||||
<%- include('../footer') -%>
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta name="viewport" content="width=device-width,initial-scale=1">
|
||||
<title>Search example</title>
|
||||
<style type="text/css">
|
||||
body {
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta name="viewport" content="width=device-width,initial-scale=1">
|
||||
<title><%= title %></title>
|
||||
<style media="screen">
|
||||
body {
|
||||
|
||||
@@ -8,7 +8,7 @@ var app = module.exports = express();
|
||||
|
||||
// create an error with .status. we
|
||||
// can then use the property in our
|
||||
// custom error handler (Connect repects this prop as well)
|
||||
// custom error handler (Connect respects this prop as well)
|
||||
|
||||
function error(status, msg) {
|
||||
var err = new Error(msg);
|
||||
@@ -55,7 +55,7 @@ var repos = [
|
||||
];
|
||||
|
||||
var users = [
|
||||
{ name: 'tobi' }
|
||||
{ name: 'tobi' }
|
||||
, { name: 'loki' }
|
||||
, { name: 'jane' }
|
||||
];
|
||||
@@ -105,7 +105,7 @@ app.use(function(err, req, res, next){
|
||||
// invoke next() and do not respond.
|
||||
app.use(function(req, res){
|
||||
res.status(404);
|
||||
res.send({ error: "Lame, can't find that" });
|
||||
res.send({ error: "Sorry, can't find that" })
|
||||
});
|
||||
|
||||
/* istanbul ignore next */
|
||||
|
||||
@@ -272,7 +272,7 @@ app.route = function route(path) {
|
||||
* In this case EJS provides a `.renderFile()` method with
|
||||
* the same signature that Express expects: `(path, options, callback)`,
|
||||
* though note that it aliases this method as `ejs.__express` internally
|
||||
* so if you're using ".ejs" extensions you dont need to do anything.
|
||||
* so if you're using ".ejs" extensions you don't need to do anything.
|
||||
*
|
||||
* Some template engines do not follow this convention, the
|
||||
* [Consolidate.js](https://github.com/tj/consolidate.js)
|
||||
|
||||
@@ -230,7 +230,7 @@ defineGetter(req, 'query', function query(){
|
||||
|
||||
/**
|
||||
* Check if the incoming request contains the "Content-Type"
|
||||
* header field, and it contains the give mime `type`.
|
||||
* header field, and it contains the given mime `type`.
|
||||
*
|
||||
* Examples:
|
||||
*
|
||||
|
||||
@@ -266,10 +266,15 @@ res.jsonp = function jsonp(obj) {
|
||||
// restrict callback charset
|
||||
callback = callback.replace(/[^\[\]\w$.]/g, '');
|
||||
|
||||
// replace chars not allowed in JavaScript that are in JSON
|
||||
body = body
|
||||
.replace(/\u2028/g, '\\u2028')
|
||||
.replace(/\u2029/g, '\\u2029');
|
||||
if (body === undefined) {
|
||||
// empty argument
|
||||
body = ''
|
||||
} else if (typeof body === 'string') {
|
||||
// replace chars not allowed in JavaScript that are in JSON
|
||||
body = body
|
||||
.replace(/\u2028/g, '\\u2028')
|
||||
.replace(/\u2029/g, '\\u2029')
|
||||
}
|
||||
|
||||
// the /**/ is a specific security mitigation for "Rosetta Flash JSONP abuse"
|
||||
// the typeof check is just to reduce client error noise
|
||||
@@ -308,7 +313,7 @@ res.sendStatus = function sendStatus(statusCode) {
|
||||
*
|
||||
* 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.sentHeader`
|
||||
* 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.
|
||||
*
|
||||
@@ -495,7 +500,7 @@ res.type = function contentType(type) {
|
||||
* res.send('<p>hey</p>');
|
||||
* },
|
||||
*
|
||||
* 'appliation/json': function(){
|
||||
* 'application/json': function () {
|
||||
* res.send({ message: 'hey' });
|
||||
* }
|
||||
* });
|
||||
@@ -598,7 +603,7 @@ res.append = function append(field, val) {
|
||||
// concat the new and prev vals
|
||||
value = Array.isArray(prev) ? prev.concat(val)
|
||||
: Array.isArray(val) ? [prev].concat(val)
|
||||
: [prev, val];
|
||||
: [prev, val]
|
||||
}
|
||||
|
||||
return this.set(field, value);
|
||||
@@ -983,7 +988,7 @@ function stringify (value, replacer, spaces, escape) {
|
||||
? JSON.stringify(value, replacer, spaces)
|
||||
: JSON.stringify(value);
|
||||
|
||||
if (escape) {
|
||||
if (escape && typeof json === 'string') {
|
||||
json = json.replace(/[<>&]/g, function (c) {
|
||||
switch (c.charCodeAt(0)) {
|
||||
case 0x3c:
|
||||
|
||||
@@ -117,6 +117,7 @@ exports.compileETag = function(val) {
|
||||
|
||||
switch (val) {
|
||||
case true:
|
||||
case 'weak':
|
||||
fn = exports.wetag;
|
||||
break;
|
||||
case false:
|
||||
@@ -124,9 +125,6 @@ exports.compileETag = function(val) {
|
||||
case 'strong':
|
||||
fn = exports.etag;
|
||||
break;
|
||||
case 'weak':
|
||||
fn = exports.wetag;
|
||||
break;
|
||||
default:
|
||||
throw new TypeError('unknown value for etag function: ' + val);
|
||||
}
|
||||
@@ -151,6 +149,7 @@ exports.compileQueryParser = function compileQueryParser(val) {
|
||||
|
||||
switch (val) {
|
||||
case true:
|
||||
case 'simple':
|
||||
fn = querystring.parse;
|
||||
break;
|
||||
case false:
|
||||
@@ -158,9 +157,6 @@ exports.compileQueryParser = function compileQueryParser(val) {
|
||||
case 'extended':
|
||||
fn = parseExtendedQueryString;
|
||||
break;
|
||||
case 'simple':
|
||||
fn = querystring.parse;
|
||||
break;
|
||||
default:
|
||||
throw new TypeError('unknown value for query parser function: ' + val);
|
||||
}
|
||||
|
||||
43
package.json
43
package.json
@@ -20,6 +20,7 @@
|
||||
"framework",
|
||||
"sinatra",
|
||||
"web",
|
||||
"http",
|
||||
"rest",
|
||||
"restful",
|
||||
"router",
|
||||
@@ -29,10 +30,10 @@
|
||||
"dependencies": {
|
||||
"accepts": "~1.3.7",
|
||||
"array-flatten": "2.1.1",
|
||||
"body-parser": "1.19.0",
|
||||
"content-disposition": "0.5.3",
|
||||
"body-parser": "1.19.1",
|
||||
"content-disposition": "0.5.4",
|
||||
"content-type": "~1.0.4",
|
||||
"cookie": "0.4.0",
|
||||
"cookie": "0.4.1",
|
||||
"cookie-signature": "1.0.6",
|
||||
"debug": "3.1.0",
|
||||
"depd": "~1.1.2",
|
||||
@@ -46,14 +47,14 @@
|
||||
"on-finished": "~2.3.0",
|
||||
"parseurl": "~1.3.3",
|
||||
"path-is-absolute": "1.0.1",
|
||||
"proxy-addr": "~2.0.5",
|
||||
"qs": "6.7.0",
|
||||
"proxy-addr": "~2.0.7",
|
||||
"qs": "6.9.6",
|
||||
"range-parser": "~1.2.1",
|
||||
"router": "2.0.0-alpha.1",
|
||||
"safe-buffer": "5.1.2",
|
||||
"send": "0.17.1",
|
||||
"serve-static": "1.14.1",
|
||||
"setprototypeof": "1.1.1",
|
||||
"safe-buffer": "5.2.1",
|
||||
"send": "0.17.2",
|
||||
"serve-static": "1.14.2",
|
||||
"setprototypeof": "1.2.0",
|
||||
"statuses": "~1.5.0",
|
||||
"type-is": "~1.6.18",
|
||||
"utils-merge": "1.0.1",
|
||||
@@ -61,22 +62,22 @@
|
||||
},
|
||||
"devDependencies": {
|
||||
"after": "0.8.2",
|
||||
"connect-redis": "3.4.1",
|
||||
"cookie-parser": "~1.4.4",
|
||||
"cookie-session": "1.3.3",
|
||||
"ejs": "2.6.1",
|
||||
"eslint": "2.13.1",
|
||||
"express-session": "1.16.1",
|
||||
"hbs": "4.0.4",
|
||||
"connect-redis": "3.4.2",
|
||||
"cookie-parser": "1.4.6",
|
||||
"cookie-session": "2.0.0",
|
||||
"ejs": "3.1.6",
|
||||
"eslint": "7.32.0",
|
||||
"express-session": "1.17.2",
|
||||
"hbs": "4.2.0",
|
||||
"istanbul": "0.4.5",
|
||||
"marked": "0.6.2",
|
||||
"marked": "0.7.0",
|
||||
"method-override": "3.0.0",
|
||||
"mocha": "5.2.0",
|
||||
"morgan": "1.9.1",
|
||||
"multiparty": "4.2.1",
|
||||
"mocha": "9.1.3",
|
||||
"morgan": "1.10.0",
|
||||
"multiparty": "4.2.2",
|
||||
"pbkdf2-password": "1.2.1",
|
||||
"should": "13.2.3",
|
||||
"supertest": "3.3.0",
|
||||
"supertest": "6.1.6",
|
||||
"vhost": "~3.0.2"
|
||||
},
|
||||
"engines": {
|
||||
|
||||
@@ -32,7 +32,7 @@ describe('Router', function(){
|
||||
var another = new Router();
|
||||
|
||||
another.get('/:bar', function(req, res){
|
||||
req.params.bar.should.equal('route');
|
||||
assert.strictEqual(req.params.bar, 'route')
|
||||
res.end();
|
||||
});
|
||||
router.use('/:foo', another);
|
||||
@@ -44,7 +44,7 @@ describe('Router', function(){
|
||||
var router = new Router();
|
||||
|
||||
router.use(function (req, res) {
|
||||
false.should.be.true()
|
||||
throw new Error('should not be called')
|
||||
});
|
||||
|
||||
router.handle({ url: '', method: 'GET' }, {}, done);
|
||||
@@ -85,7 +85,7 @@ describe('Router', function(){
|
||||
|
||||
var res = {
|
||||
send: function(val) {
|
||||
val.should.equal('foo');
|
||||
assert.strictEqual(val, 'foo')
|
||||
done();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -13,7 +13,7 @@ describe('cookie-sessions', function () {
|
||||
it('should set a session cookie', function (done) {
|
||||
request(app)
|
||||
.get('/')
|
||||
.expect('Set-Cookie', /express:sess=/)
|
||||
.expect('Set-Cookie', /session=/)
|
||||
.expect(200, done)
|
||||
})
|
||||
|
||||
|
||||
@@ -11,6 +11,15 @@ describe('downloads', function(){
|
||||
})
|
||||
})
|
||||
|
||||
describe('GET /files/notes/groceries.txt', function () {
|
||||
it('should have a download header', function (done) {
|
||||
request(app)
|
||||
.get('/files/notes/groceries.txt')
|
||||
.expect('Content-Disposition', 'attachment; filename="groceries.txt"')
|
||||
.expect(200, done)
|
||||
})
|
||||
})
|
||||
|
||||
describe('GET /files/amazing.txt', function(){
|
||||
it('should have a download header', function(done){
|
||||
request(app)
|
||||
|
||||
@@ -97,9 +97,9 @@ describe('web-service', function(){
|
||||
describe('when requesting an invalid route', function(){
|
||||
it('should respond with 404 json', function(done){
|
||||
request(app)
|
||||
.get('/api/something?api-key=bar')
|
||||
.expect('Content-Type', /json/)
|
||||
.expect(404, '{"error":"Lame, can\'t find that"}', done)
|
||||
.get('/api/something?api-key=bar')
|
||||
.expect('Content-Type', /json/)
|
||||
.expect(404, '{"error":"Sorry, can\'t find that"}', done)
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
@@ -26,7 +26,7 @@ describe('HEAD', function(){
|
||||
});
|
||||
|
||||
request(app)
|
||||
.get('/tobi')
|
||||
.head('/tobi')
|
||||
.expect(200, function(err, res){
|
||||
if (err) return done(err);
|
||||
var headers = res.headers;
|
||||
|
||||
@@ -5,10 +5,6 @@ describe('app.listen()', function(){
|
||||
it('should wrap with an HTTP server', function(done){
|
||||
var app = express();
|
||||
|
||||
app.get('/tobi', function(req, res){
|
||||
res.end('got tobi!');
|
||||
});
|
||||
|
||||
var server = app.listen(9999, function(){
|
||||
server.close();
|
||||
done();
|
||||
|
||||
@@ -144,7 +144,7 @@ describe('app', function(){
|
||||
});
|
||||
|
||||
app.param('user', function(req, res, next, user) {
|
||||
next(new Error('invalid invokation'));
|
||||
next(new Error('invalid invocation'))
|
||||
});
|
||||
|
||||
app.post('/:user', function(req, res, next) {
|
||||
|
||||
@@ -188,6 +188,35 @@ describe('app.router', function(){
|
||||
.get('/user/10/edit')
|
||||
.expect('editing user 10', done);
|
||||
})
|
||||
|
||||
it.skip('should ensure regexp matches path prefix', function (done) {
|
||||
var app = express()
|
||||
var p = []
|
||||
|
||||
app.use(/\/api.*/, function (req, res, next) {
|
||||
p.push('a')
|
||||
next()
|
||||
})
|
||||
app.use(/api/, function (req, res, next) {
|
||||
p.push('b')
|
||||
next()
|
||||
})
|
||||
app.use(/\/test/, function (req, res, next) {
|
||||
p.push('c')
|
||||
next()
|
||||
})
|
||||
app.use(function (req, res) {
|
||||
res.end()
|
||||
})
|
||||
|
||||
request(app)
|
||||
.get('/test/api/1234')
|
||||
.expect(200, function (err) {
|
||||
if (err) return done(err)
|
||||
assert.deepEqual(p, ['c'])
|
||||
done()
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
describe('case sensitivity', function(){
|
||||
|
||||
@@ -429,7 +429,7 @@ describe('express.static()', function () {
|
||||
|
||||
describe('lastModified', function () {
|
||||
describe('when false', function () {
|
||||
it('should not include Last-Modifed', function (done) {
|
||||
it('should not include Last-Modified', function (done) {
|
||||
request(createApp(fixtures, { 'lastModified': false }))
|
||||
.get('/nums.txt')
|
||||
.expect(utils.shouldNotHaveHeader('Last-Modified'))
|
||||
@@ -438,7 +438,7 @@ describe('express.static()', function () {
|
||||
})
|
||||
|
||||
describe('when true', function () {
|
||||
it('should include Last-Modifed', function (done) {
|
||||
it('should include Last-Modified', function (done) {
|
||||
request(createApp(fixtures, { 'lastModified': true }))
|
||||
.get('/nums.txt')
|
||||
.expect('Last-Modified', /^\w{3}, \d+ \w+ \d+ \d+:\d+:\d+ \w+$/)
|
||||
|
||||
@@ -115,6 +115,19 @@ describe('res', function(){
|
||||
.get('/')
|
||||
.expect(200, optionsCopy, done)
|
||||
})
|
||||
|
||||
it('should throw an error with invalid maxAge', function (done) {
|
||||
var app = express()
|
||||
|
||||
app.use(function (req, res) {
|
||||
res.cookie('name', 'tobi', { maxAge: 'foobar' })
|
||||
res.end()
|
||||
})
|
||||
|
||||
request(app)
|
||||
.get('/')
|
||||
.expect(500, /option maxAge is invalid/, done)
|
||||
})
|
||||
})
|
||||
|
||||
describe('signed', function(){
|
||||
|
||||
@@ -122,6 +122,21 @@ describe('res', function(){
|
||||
.expect('Content-Type', 'application/json; charset=utf-8')
|
||||
.expect(200, '{"\\u0026":"\\u003cscript\\u003e"}', done)
|
||||
})
|
||||
|
||||
it('should not break undefined escape', function (done) {
|
||||
var app = express()
|
||||
|
||||
app.enable('json escape')
|
||||
|
||||
app.use(function (req, res) {
|
||||
res.json(undefined)
|
||||
})
|
||||
|
||||
request(app)
|
||||
.get('/')
|
||||
.expect('Content-Type', 'application/json; charset=utf-8')
|
||||
.expect(200, '', done)
|
||||
})
|
||||
})
|
||||
|
||||
describe('"json replacer" setting', function(){
|
||||
|
||||
@@ -156,89 +156,93 @@ describe('res', function(){
|
||||
.expect(200, /cb\(\{"hello":"world"\}\);$/, done);
|
||||
})
|
||||
|
||||
describe('when given primitives', function(){
|
||||
it('should respond with json', function(done){
|
||||
var app = express();
|
||||
describe('when given undefined', function () {
|
||||
it('should invoke callback with no arguments', function (done) {
|
||||
var app = express()
|
||||
|
||||
app.use(function(req, res){
|
||||
res.jsonp(null);
|
||||
});
|
||||
app.use(function (req, res) {
|
||||
res.jsonp(undefined)
|
||||
})
|
||||
|
||||
request(app)
|
||||
.get('/')
|
||||
.expect('Content-Type', 'application/json; charset=utf-8')
|
||||
.expect(200, 'null', done)
|
||||
.get('/?callback=cb')
|
||||
.expect('Content-Type', 'text/javascript; charset=utf-8')
|
||||
.expect(200, /cb\(\)/, done)
|
||||
})
|
||||
})
|
||||
|
||||
describe('when given an array', function(){
|
||||
it('should respond with json', function(done){
|
||||
var app = express();
|
||||
describe('when given null', function () {
|
||||
it('should invoke callback with null', function (done) {
|
||||
var app = express()
|
||||
|
||||
app.use(function(req, res){
|
||||
res.jsonp(['foo', 'bar', 'baz']);
|
||||
});
|
||||
app.use(function (req, res) {
|
||||
res.jsonp(null)
|
||||
})
|
||||
|
||||
request(app)
|
||||
.get('/')
|
||||
.expect('Content-Type', 'application/json; charset=utf-8')
|
||||
.expect(200, '["foo","bar","baz"]', done)
|
||||
.get('/?callback=cb')
|
||||
.expect('Content-Type', 'text/javascript; charset=utf-8')
|
||||
.expect(200, /cb\(null\)/, done)
|
||||
})
|
||||
})
|
||||
|
||||
describe('when given an object', function(){
|
||||
it('should respond with json', function(done){
|
||||
var app = express();
|
||||
describe('when given a string', function () {
|
||||
it('should invoke callback with a string', function (done) {
|
||||
var app = express()
|
||||
|
||||
app.use(function(req, res){
|
||||
res.jsonp({ name: 'tobi' });
|
||||
});
|
||||
app.use(function (req, res) {
|
||||
res.jsonp('tobi')
|
||||
})
|
||||
|
||||
request(app)
|
||||
.get('/')
|
||||
.expect('Content-Type', 'application/json; charset=utf-8')
|
||||
.expect(200, '{"name":"tobi"}', done)
|
||||
.get('/?callback=cb')
|
||||
.expect('Content-Type', 'text/javascript; charset=utf-8')
|
||||
.expect(200, /cb\("tobi"\)/, done)
|
||||
})
|
||||
})
|
||||
|
||||
describe('when given primitives', function(){
|
||||
it('should respond with json for null', function(done){
|
||||
var app = express();
|
||||
describe('when given a number', function () {
|
||||
it('should invoke callback with a number', function (done) {
|
||||
var app = express()
|
||||
|
||||
app.use(function(req, res){
|
||||
res.jsonp(null);
|
||||
});
|
||||
app.use(function (req, res) {
|
||||
res.jsonp(42)
|
||||
})
|
||||
|
||||
request(app)
|
||||
.get('/')
|
||||
.expect('Content-Type', 'application/json; charset=utf-8')
|
||||
.expect(200, 'null', done)
|
||||
.get('/?callback=cb')
|
||||
.expect('Content-Type', 'text/javascript; charset=utf-8')
|
||||
.expect(200, /cb\(42\)/, done)
|
||||
})
|
||||
})
|
||||
|
||||
it('should respond with json for Number', function(done){
|
||||
var app = express();
|
||||
describe('when given an array', function () {
|
||||
it('should invoke callback with an array', function (done) {
|
||||
var app = express()
|
||||
|
||||
app.use(function(req, res){
|
||||
res.jsonp(300);
|
||||
});
|
||||
app.use(function (req, res) {
|
||||
res.jsonp(['foo', 'bar', 'baz'])
|
||||
})
|
||||
|
||||
request(app)
|
||||
.get('/')
|
||||
.expect('Content-Type', 'application/json; charset=utf-8')
|
||||
.expect(200, '300', done)
|
||||
.get('/?callback=cb')
|
||||
.expect('Content-Type', 'text/javascript; charset=utf-8')
|
||||
.expect(200, /cb\(\["foo","bar","baz"\]\)/, done)
|
||||
})
|
||||
})
|
||||
|
||||
it('should respond with json for String', function(done){
|
||||
var app = express();
|
||||
describe('when given an object', function () {
|
||||
it('should invoke callback with an object', function (done) {
|
||||
var app = express()
|
||||
|
||||
app.use(function(req, res){
|
||||
res.jsonp('str');
|
||||
});
|
||||
app.use(function (req, res) {
|
||||
res.jsonp({ name: 'tobi' })
|
||||
})
|
||||
|
||||
request(app)
|
||||
.get('/')
|
||||
.expect('Content-Type', 'application/json; charset=utf-8')
|
||||
.expect(200, '"str"', done)
|
||||
.get('/?callback=cb')
|
||||
.expect('Content-Type', 'text/javascript; charset=utf-8')
|
||||
.expect(200, /cb\(\{"name":"tobi"\}\)/, done)
|
||||
})
|
||||
})
|
||||
|
||||
@@ -262,6 +266,21 @@ describe('res', function(){
|
||||
.expect('Content-Type', 'text/javascript; charset=utf-8')
|
||||
.expect(200, /foo\({"\\u0026":"\\u2028\\u003cscript\\u003e\\u2029"}\)/, done)
|
||||
})
|
||||
|
||||
it('should not break undefined escape', function (done) {
|
||||
var app = express()
|
||||
|
||||
app.enable('json escape')
|
||||
|
||||
app.use(function (req, res) {
|
||||
res.jsonp(undefined)
|
||||
})
|
||||
|
||||
request(app)
|
||||
.get('/?callback=cb')
|
||||
.expect('Content-Type', 'text/javascript; charset=utf-8')
|
||||
.expect(200, /cb\(\)/, done)
|
||||
})
|
||||
})
|
||||
|
||||
describe('"json replacer" setting', function(){
|
||||
|
||||
Reference in New Issue
Block a user