Compare commits

...

103 Commits

Author SHA1 Message Date
Douglas Christopher Wilson
351396f971 4.16.2 2017-10-09 22:55:18 -04:00
Douglas Christopher Wilson
b97faff6e2 perf: skip parsing of entire "X-Forwarded-Proto" header 2017-10-09 22:43:23 -04:00
David Wood
b7817ab1b0 Fix TypeError in res.send when given Buffer and ETag header set
fixes #3445
2017-10-09 22:11:49 -04:00
Douglas Christopher Wilson
48aba21ea4 docs: add missing history for res.download change 2017-10-04 23:09:22 -04:00
Douglas Christopher Wilson
de129c289d tests: run mocha with --no-exit to detect hangs
closes #3439
2017-10-01 00:48:29 -04:00
Douglas Christopher Wilson
e3f7f51f5f 4.16.1 2017-09-29 16:23:23 -04:00
Douglas Christopher Wilson
6f823e409c deps: serve-static@1.13.1
closes #3436
2017-09-29 16:12:06 -04:00
Douglas Christopher Wilson
6d9b13cced deps: send@0.16.1 2017-09-29 15:56:55 -04:00
Douglas Christopher Wilson
f974d22c66 4.16.0 2017-09-28 13:57:23 -04:00
Douglas Christopher Wilson
8d4ceb623d docs: add more information to installation 2017-09-28 13:55:15 -04:00
Douglas Christopher Wilson
c0136d8b48 Add express.json and express.urlencoded to parse bodies
closes #2211
2017-09-28 13:22:36 -04:00
Douglas Christopher Wilson
86f5df00ed deps: serve-static@1.13.0
closes #3197
2017-09-28 13:08:38 -04:00
Daniel Tschinder
41964580a8 deps: send@0.16.0
closes #3431
closes #3435
2017-09-28 12:39:05 -04:00
Douglas Christopher Wilson
ddeb71301c tests: add maxAge option tests for res.sendFile 2017-09-28 12:32:27 -04:00
Greg Guthe
7154014785 Add "escape json" setting for res.json and res.jsonp
closes #3268
closes #3269
2017-09-28 12:03:42 -04:00
Douglas Christopher Wilson
628438d8d8 deps: update example dependencies 2017-09-28 11:36:20 -04:00
Aaron Clover
a24fd0ca6c Add options to res.download
closes #3327
closes #3370
2017-09-28 11:11:08 -04:00
Douglas Christopher Wilson
95fb5cc268 perf: remove dead .charset set in res.jsonp 2017-09-28 10:30:10 -04:00
chainhelen
44591fee23 deps: vary@~1.1.2
closes #3434
2017-09-28 10:08:23 -04:00
Hrvoje Šimić
2df1ad26a5 Improve error messages when non-function provided as middleware
closes #3426
2017-09-28 09:20:37 -04:00
Douglas Christopher Wilson
12c3712468 Use safe-buffer for improved Buffer API 2017-09-28 08:26:39 -04:00
Hrvoje Šimić
fa272edf84 docs: fix typo in jsdoc comment
closes #3430
2017-09-28 08:05:54 -04:00
Lawrence Page
d9d09b8b90 perf: re-use options object when generating ETags
closes #3313
closes #3314
2017-09-28 08:04:42 -04:00
Douglas Christopher Wilson
02a9d5fb28 deps: proxy-addr@~2.0.2
closes #3432
2017-09-28 01:18:04 -04:00
Douglas Christopher Wilson
c2f4fb5356 deps: finalhandler@1.1.0 2017-09-28 00:42:05 -04:00
Douglas Christopher Wilson
673d51f4f0 deps: utils-merge@1.0.1 2017-09-28 00:19:30 -04:00
Douglas Christopher Wilson
5cc761c865 deps: parseurl@~1.3.2 2017-09-28 00:04:47 -04:00
Douglas Christopher Wilson
ad7d96db47 deps: qs@6.5.1 2017-09-27 21:31:39 -04:00
Douglas Christopher Wilson
e62bb8bf9f deps: etag@~1.8.1 2017-09-27 21:30:43 -04:00
Douglas Christopher Wilson
70589c3aef deps: content-type@~1.0.4 2017-09-27 21:30:08 -04:00
Douglas Christopher Wilson
9a99c15270 deps: accepts@~1.3.4 2017-09-27 21:28:25 -04:00
Douglas Christopher Wilson
550043c217 deps: setprototypeof@1.1.0 2017-09-25 21:14:00 -04:00
Douglas Christopher Wilson
48940e6120 Skip Buffer encoding when not generating ETag for small response 2017-09-25 21:12:47 -04:00
Douglas Christopher Wilson
80f1ea9bec Improve error message when autoloading invalid view engine
fixes #3403
2017-09-25 21:11:33 -04:00
Douglas Christopher Wilson
c3fb7e5adc build: test against Node.js 9.x nightly 2017-09-25 21:06:00 -04:00
Douglas Christopher Wilson
94fdb674b1 build: support Node.js 8.x 2017-09-25 20:57:54 -04:00
Douglas Christopher Wilson
ea3d605652 4.15.5 2017-09-25 01:04:38 -04:00
Douglas Christopher Wilson
40435ec997 deps: serve-static@1.12.6 2017-09-22 20:28:52 -04:00
Douglas Christopher Wilson
7137bf567d deps: send@0.15.6 2017-09-22 20:27:37 -04:00
Douglas Christopher Wilson
bd1672f0a4 deps: finalhandler@~1.0.6 2017-09-22 20:26:30 -04:00
Douglas Christopher Wilson
9395db4c22 deps: debug@2.6.9 2017-09-22 20:25:18 -04:00
Kunal Pathak
19a2eeb476 tests: check render error without engine-specific message
closes #3251
2017-09-21 22:45:26 -04:00
Douglas Christopher Wilson
d7da22550d build: should@13.1.0 2017-09-21 20:49:14 -04:00
Douglas Christopher Wilson
961dbff904 deps: serve-static@1.12.5 2017-09-21 20:48:23 -04:00
Douglas Christopher Wilson
9e0fa7f1ca deps: send@0.15.5 2017-09-21 20:46:42 -04:00
Douglas Christopher Wilson
9e067ad2cb deps: fresh@0.5.2 2017-09-21 20:45:32 -04:00
Douglas Christopher Wilson
de5fb62b1a deps: update example dependencies 2017-09-17 20:13:05 -04:00
Douglas Christopher Wilson
b208b24f83 build: should@13.0.1 2017-09-13 20:09:33 -04:00
Douglas Christopher Wilson
78e55108e4 build: mocha@3.5.3 2017-09-13 20:03:42 -04:00
Douglas Christopher Wilson
48817a798f build: remove minor pin for nightly 2017-08-17 22:03:40 -04:00
Douglas Christopher Wilson
a4bd4373b2 4.15.4 2017-08-06 22:03:53 -04:00
Douglas Christopher Wilson
a50f1098d0 deps: serve-static@1.12.4 2017-08-06 02:38:02 -04:00
Douglas Christopher Wilson
e2d725e016 deps: send@0.15.4 2017-08-06 02:37:10 -04:00
Douglas Christopher Wilson
e0066227f7 lint: remove all unused varaibles 2017-08-06 00:19:32 -04:00
Douglas Christopher Wilson
44881fabe3 docs: update collaborator guide for lint script 2017-08-06 00:18:57 -04:00
Douglas Christopher Wilson
1dbaae51dd deps: update example dependencies 2017-08-05 23:54:31 -04:00
Douglas Christopher Wilson
56e90e3c72 lint: add eslint rules that cover editorconfig 2017-08-05 23:37:39 -04:00
Daniel Walasek
713d2aed93 tests: fix incorrect should usage
closes #3387
2017-08-05 20:10:35 -04:00
Douglas Christopher Wilson
e0aa8bf74e build: mocha@3.5.0 2017-08-04 00:26:50 -04:00
Douglas Christopher Wilson
85770a71fc deps: finalhandler@~1.0.4 2017-08-04 00:25:59 -04:00
Hung HOANG
daf66beda4 examples: fix path join in ejs example
fixes #3382
closes #3383
closes #3385
2017-08-03 21:20:55 -04:00
Douglas Christopher Wilson
b2af101821 build: ejs@2.5.7 2017-08-02 23:32:44 -04:00
Douglas Christopher Wilson
3eb16c233c deps: depd@~1.1.1 2017-08-02 23:30:47 -04:00
Douglas Christopher Wilson
582381bceb deps: proxy-addr@~1.1.5 2017-07-26 13:09:46 -04:00
Owen Luke
5e16f400f1 examples: use 1-based visitor count in cookie-sessions
closes #3312
2017-07-26 13:05:41 -04:00
Piper Chester
43dff4ceb3 docs: fix GitHub capitalization
closes #3353
2017-07-26 11:53:05 -04:00
Douglas Christopher Wilson
04beebb2c0 build: Node.js@6.11 2017-07-26 11:52:42 -04:00
Douglas Christopher Wilson
1adee79e63 deps: update example dependencies 2017-06-30 23:58:01 -04:00
Douglas Christopher Wilson
bd5951e603 deps: debug@2.6.8
closes #3286
closes #3337
2017-06-30 23:51:18 -04:00
Douglas Christopher Wilson
deffce5704 deps: qs@6.5.0 2017-06-30 23:47:12 -04:00
Douglas Christopher Wilson
48777dc377 build: mocha@3.4.2 2017-06-04 19:12:30 -04:00
Douglas Christopher Wilson
9467a392e3 build: Node.js@7.10 2017-06-04 19:09:25 -04:00
Owen Luke
9f019c8c69 examples: add comment about Redis install in examples
closes #3310
2017-05-17 21:18:35 -04:00
Owen Luke
cf37240e73 examples: fix reference error in view-constructor
closes #3310
2017-05-17 21:17:47 -04:00
Owen Luke
60f87f8074 examples: fix posts link in route-separation example
closes #3310
2017-05-17 21:17:16 -04:00
Owen Luke
fde8f647d3 examples: fix route in params example
closes #3310
2017-05-17 21:14:47 -04:00
Douglas Christopher Wilson
6da454c7fb 4.15.3 2017-05-17 02:14:11 -04:00
Douglas Christopher Wilson
5cf473dc5d deps: debug@2.6.7 2017-05-17 02:08:50 -04:00
Douglas Christopher Wilson
65494692c2 build: mocha@3.4.1 2017-05-17 01:57:31 -04:00
Douglas Christopher Wilson
bc2986fe59 deps: finalhandler@~1.0.3 2017-05-17 01:56:36 -04:00
Douglas Christopher Wilson
58cfc9911b deps: serve-static@1.12.3 2017-05-17 01:47:17 -04:00
Douglas Christopher Wilson
ad4456c491 deps: send@0.15.3 2017-05-17 01:46:34 -04:00
Douglas Christopher Wilson
1ba9a9ac23 deps: update example dependencies 2017-05-17 01:28:21 -04:00
Oz Michaeli
ae0b630ac7 Fix error when res.set cannot add charset to Content-Type
fixes #3303
closes #3305
closes #3307
2017-05-14 23:58:25 -04:00
Douglas Christopher Wilson
5ea2a8ff8e build: Node.js@7.9 2017-05-14 23:29:13 -04:00
Tony Anisimov
de41c0bfa4 Fix res.cookie jsdoc comment
closes #3304
2017-05-11 15:51:03 -04:00
Colin Richardson
a13938eed7 tests: add tests for res.location('back')
closes #3292
closes #3293
2017-05-07 19:26:33 -04:00
Douglas Christopher Wilson
1b6e7004b7 deps: send@0.15.2 2017-04-27 01:11:58 -04:00
Douglas Christopher Wilson
2d1dade36a deps: serve-static@1.12.2 2017-04-27 00:00:57 -04:00
Douglas Christopher Wilson
df4f2719db deps: type-is@~1.6.15 2017-04-26 23:49:41 -04:00
asaf david
c087a45b9c Fix typo in variable name setPrototypeOf
closes #3266
2017-03-31 22:27:00 -04:00
Douglas Christopher Wilson
347d4db3ca deps: proxy-addr@~1.1.4 2017-03-28 22:56:32 -04:00
Jamie Barton
aabf7802a9 docs: fix the security issues heading format
closes #3256
2017-03-24 17:07:06 -04:00
Jamie Barton
3763d73a1f examples: replace jade with hbs in mvc example
fixes #3181
closes #3185
closes #3243
closes #3245
closes #3249
2017-03-23 00:45:23 -04:00
Douglas Christopher Wilson
8acaa9a3ea deps: finalhandler@~1.0.1
fixes #3252
2017-03-22 02:12:06 -04:00
Douglas Christopher Wilson
dbf092d3ea deps: vary@~1.1.1 2017-03-22 02:10:43 -04:00
Wes Todd
efd7032f71 build: Add .editorconfig
closes #3221
2017-03-19 16:46:37 -04:00
Douglas Christopher Wilson
2189ff14a9 lint: remove trailing new lines from docs 2017-03-19 16:45:58 -04:00
Jamie Barton
245fa8942a examples: replace jade with ejs in route-separation
closes #3241
2017-03-17 00:09:50 -04:00
Douglas Christopher Wilson
1b6ad08095 deps: debug@2.6.3 2017-03-14 23:53:19 -04:00
Douglas Christopher Wilson
a1fffda3f2 build: should@11.2.1 2017-03-14 23:46:29 -04:00
Jamie Barton
f44368f8be examples: replace jade with ejs in view-locals
closes #3240
2017-03-09 23:41:15 -05:00
Jamie Barton
64dd446aa8 docs: remove dead link to translated readme
closes #3239
2017-03-09 23:37:06 -05:00
114 changed files with 1036 additions and 409 deletions

11
.editorconfig Normal file
View File

@@ -0,0 +1,11 @@
# http://editorconfig.org
root = true
[*]
charset = utf-8
insert_final_newline = true
trim_trailing_whitespace = true
[{*.js,*.json,*.yml}]
indent_size = 2
indent_style = space

2
.eslintignore Normal file
View File

@@ -0,0 +1,2 @@
coverage
node_modules

8
.eslintrc Normal file
View File

@@ -0,0 +1,8 @@
{
"rules": {
"eol-last": "error",
"indent": ["error", 2, { "SwitchCase": 1 }],
"no-trailing-spaces": "error",
"no-unused-vars": ["error", { "vars": "all", "args": "none", "ignoreRestSiblings": true }]
}
}

1
.gitignore vendored
View File

@@ -15,6 +15,7 @@ Desktop.ini
# npm
node_modules
package-lock.json
*.log
*.gz

View File

@@ -7,11 +7,14 @@ node_js:
- "3.3"
- "4.8"
- "5.12"
- "6.10"
- "7.6"
- "6.11"
- "7.10"
- "8.4"
matrix:
include:
- node_js: "8.0"
- node_js: "8"
env: "NVM_NODEJS_ORG_MIRROR=https://nodejs.org/download/nightly"
- node_js: "9"
env: "NVM_NODEJS_ORG_MIRROR=https://nodejs.org/download/nightly"
allow_failures:
# Allow the nightly installs to fail
@@ -21,11 +24,16 @@ cache:
directories:
- node_modules
before_install:
# Skip updating shrinkwrap / lock
- "npm config set shrinkwrap false"
# Remove all non-test dependencies
- "npm rm --save-dev connect-redis"
# Update Node.js modules
- "test ! -d node_modules || npm prune"
- "test ! -d node_modules || npm rebuild"
script: "npm run-script test-ci"
script:
- "npm run test-ci"
- "npm run lint"
after_script: "npm install coveralls@2.10.0 && cat ./coverage/lcov.info | coveralls"

View File

@@ -6,7 +6,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/).
* Follow the [JavaScript Standard Style](http://standardjs.com/) and `npm run lint`.
* If you fix a bug, add a test.
## Branches
@@ -27,7 +27,9 @@ a future release of Express.
each new issue you work on, although not compulsory.
4. To run the test suite, first install the dependencies by running `npm install`,
then run `npm test`.
5. If the tests pass, you can commit your changes to your fork and then create
5. Ensure your code is linted by running `npm run lint` -- fix any issue you
see listed.
6. If the tests pass, you can commit your changes to your fork and then create
a pull request from there. Make sure to reference your issue from the pull
request comments by including the issue number e.g. `#123`.

View File

@@ -12,7 +12,7 @@ contributors can be involved in decision making.
* A **Contributor** is any individual creating or commenting on an issue or pull request.
* 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
* A **TC (Technical Committee)** is a group of committers representing the required technical
expertise to resolve rare disputes.
# Logging Issues
@@ -36,24 +36,24 @@ pull requests.
No pull request can be merged without being reviewed.
For non-trivial contributions, pull requests should sit for at least 36 hours to ensure that
contributors in other timezones have time to review. Consideration should also be given to
weekends and other holiday periods to ensure active committers all have reasonable time to
contributors in other timezones have time to review. Consideration should also be given to
weekends and other holiday periods to ensure active committers all have reasonable time to
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
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
During 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.
In the case of an objection being raised in a pull request by another committer, all involved
committers should seek to arrive at a consensus by way of addressing concerns being expressed
In the case of an objection being raised in a pull request by another committer, all involved
committers should seek to arrive at a consensus by way of addressing concerns being expressed
by discussion, compromise on the proposed change, or withdrawal of the proposed change.
If a contribution is controversial and committers cannot agree about how to get it to land
or if it should land then it should be escalated to the TC. TC members should regularly
discuss pending contributions in order to find a resolution. It is expected that only a
small minority of issues be brought to the TC for resolution and that discussion and
discuss pending contributions in order to find a resolution. It is expected that only a
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
@@ -66,20 +66,20 @@ proper review, and have other committers merge their pull requests.
# TC Process
The TC uses a "consensus seeking" process for issues that are escalated to the TC.
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.
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
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
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.
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
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.

View File

@@ -1,3 +1,129 @@
4.16.2 / 2017-10-09
===================
* Fix `TypeError` in `res.send` when given `Buffer` and `ETag` header set
* perf: skip parsing of entire `X-Forwarded-Proto` header
4.16.1 / 2017-09-29
===================
* deps: send@0.16.1
* deps: serve-static@1.13.1
- Fix regression when `root` is incorrectly set to a file
- deps: send@0.16.1
4.16.0 / 2017-09-28
===================
* Add `"json escape"` setting for `res.json` and `res.jsonp`
* Add `express.json` and `express.urlencoded` to parse bodies
* Add `options` argument to `res.download`
* Improve error message when autoloading invalid view engine
* Improve error messages when non-function provided as middleware
* Skip `Buffer` encoding when not generating ETag for small response
* Use `safe-buffer` for improved Buffer API
* deps: accepts@~1.3.4
- deps: mime-types@~2.1.16
* deps: content-type@~1.0.4
- perf: remove argument reassignment
- perf: skip parameter parsing when no parameters
* deps: etag@~1.8.1
- perf: replace regular expression with substring
* deps: finalhandler@1.1.0
- Use `res.headersSent` when available
* deps: parseurl@~1.3.2
- perf: reduce overhead for full URLs
- perf: unroll the "fast-path" `RegExp`
* deps: proxy-addr@~2.0.2
- Fix trimming leading / trailing OWS in `X-Forwarded-For`
- deps: forwarded@~0.1.2
- deps: ipaddr.js@1.5.2
- perf: reduce overhead when no `X-Forwarded-For` header
* deps: qs@6.5.1
- Fix parsing & compacting very deep objects
* deps: send@0.16.0
- Add 70 new types for file extensions
- Add `immutable` option
- Fix missing `</html>` in default error & redirects
- Set charset as "UTF-8" for .js and .json
- Use instance methods on steam to check for listeners
- deps: mime@1.4.1
- perf: improve path validation speed
* deps: serve-static@1.13.0
- Add 70 new types for file extensions
- Add `immutable` option
- Set charset as "UTF-8" for .js and .json
- deps: send@0.16.0
* deps: setprototypeof@1.1.0
* deps: utils-merge@1.0.1
* deps: vary@~1.1.2
- perf: improve header token parsing speed
* perf: re-use options object when generating ETags
* perf: remove dead `.charset` set in `res.jsonp`
4.15.5 / 2017-09-24
===================
* deps: debug@2.6.9
* deps: finalhandler@~1.0.6
- deps: debug@2.6.9
- deps: parseurl@~1.3.2
* deps: fresh@0.5.2
- Fix handling of modified headers with invalid dates
- perf: improve ETag match loop
- perf: improve `If-None-Match` token parsing
* deps: send@0.15.6
- Fix handling of modified headers with invalid dates
- deps: debug@2.6.9
- deps: etag@~1.8.1
- deps: fresh@0.5.2
- perf: improve `If-Match` token parsing
* deps: serve-static@1.12.6
- deps: parseurl@~1.3.2
- deps: send@0.15.6
- perf: improve slash collapsing
4.15.4 / 2017-08-06
===================
* deps: debug@2.6.8
* deps: depd@~1.1.1
- Remove unnecessary `Buffer` loading
* deps: finalhandler@~1.0.4
- deps: debug@2.6.8
* deps: proxy-addr@~1.1.5
- Fix array argument being altered
- deps: ipaddr.js@1.4.0
* deps: qs@6.5.0
* deps: send@0.15.4
- deps: debug@2.6.8
- deps: depd@~1.1.1
- deps: http-errors@~1.6.2
* deps: serve-static@1.12.4
- deps: send@0.15.4
4.15.3 / 2017-05-16
===================
* Fix error when `res.set` cannot add charset to `Content-Type`
* deps: debug@2.6.7
- Fix `DEBUG_MAX_ARRAY_LENGTH`
- deps: ms@2.0.0
* deps: finalhandler@~1.0.3
- Fix missing `</html>` in HTML document
- deps: debug@2.6.7
* deps: proxy-addr@~1.1.4
- deps: ipaddr.js@1.3.0
* deps: send@0.15.3
- deps: debug@2.6.7
- deps: ms@2.0.0
* deps: serve-static@1.12.3
- deps: send@0.15.3
* deps: type-is@~1.6.15
- deps: mime-types@~2.1.15
* deps: vary@~1.1.1
- perf: hoist regular expression
4.15.2 / 2017-03-06
===================

View File

@@ -21,10 +21,22 @@ app.listen(3000)
## Installation
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.
Installation is done using the
[`npm install` command](https://docs.npmjs.com/getting-started/installing-npm-packages-locally):
```bash
$ npm install express
```
Follow [our installing guide](http://expressjs.com/en/starter/installing.html)
for more information.
## Features
* Robust routing
@@ -39,15 +51,14 @@ $ npm install express
* [Website and Documentation](http://expressjs.com/) - [[website repo](https://github.com/expressjs/expressjs.com)]
* [#express](https://webchat.freenode.net/?channels=express) on freenode IRC
* [Github Organization](https://github.com/expressjs) for Official Middleware & Modules
* [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
* [Русскоязычная документация](http://jsman.ru/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).
###Security Issues
### Security Issues
If you discover a security vulnerability in Express, please see [Security Policies and Procedures](Security.md).

View File

@@ -7,12 +7,14 @@ environment:
- nodejs_version: "3.3"
- nodejs_version: "4.8"
- nodejs_version: "5.12"
- nodejs_version: "6.10"
- nodejs_version: "7.6"
- nodejs_version: "6.11"
- nodejs_version: "7.10"
- nodejs_version: "8.4"
cache:
- node_modules
install:
- ps: Install-Product node $env:nodejs_version
- npm config set shrinkwrap false
- npm rm --save-dev connect-redis
- if exist node_modules npm prune
- if exist node_modules npm rebuild
@@ -22,4 +24,5 @@ test_script:
- node --version
- npm --version
- npm run test-ci
- npm run lint
version: "{build}"

View File

@@ -1,5 +1,4 @@
var http = require('http');
var express = require('..');
var app = express();
@@ -14,10 +13,8 @@ while (n--) {
});
}
var body = new Buffer('Hello World');
app.use(function(req, res, next){
res.send(body);
res.send('Hello World')
});
app.listen(3333);

View File

@@ -3,7 +3,6 @@
*/
var express = require('../..');
var bodyParser = require('body-parser');
var hash = require('pbkdf2-password')()
var path = require('path');
var session = require('express-session');
@@ -17,7 +16,7 @@ app.set('views', path.join(__dirname, 'views'));
// middleware
app.use(bodyParser.urlencoded({ extended: false }));
app.use(express.urlencoded({ extended: false }))
app.use(session({
resave: false, // don't save session if unmodified
saveUninitialized: false, // don't create session until something stored

View File

@@ -4,4 +4,4 @@ users.push({ name: 'Tobi' });
users.push({ name: 'Loki' });
users.push({ name: 'Jane' });
module.exports = users;
module.exports = users;

View File

@@ -15,9 +15,8 @@ app.use(count);
// custom middleware
function count(req, res) {
req.session.count = req.session.count || 0;
var n = req.session.count++;
res.send('viewed ' + n + ' times\n');
req.session.count = (req.session.count || 0) + 1
res.send('viewed ' + req.session.count + ' times\n')
}
/* istanbul ignore next */

View File

@@ -6,7 +6,6 @@ var express = require('../../');
var app = module.exports = express();
var logger = require('morgan');
var cookieParser = require('cookie-parser');
var bodyParser = require('body-parser');
// custom log format
if ('test' != process.env.NODE_ENV) app.use(logger(':method :url'));
@@ -18,7 +17,7 @@ if ('test' != process.env.NODE_ENV) app.use(logger(':method :url'));
app.use(cookieParser('my secret here'));
// parses x-www-form-urlencoded
app.use(bodyParser.urlencoded({ extended: false }));
app.use(express.urlencoded({ extended: false }))
app.get('/', function(req, res){
if (req.cookies.remember) {

View File

@@ -26,7 +26,7 @@ app.set('views', path.join(__dirname, 'views'));
// Path to our public directory
app.use(express.static(path.join(__dirname + 'public')));
app.use(express.static(path.join(__dirname, 'public')));
// Without this you would need to
// supply the extension to res.render()

View File

@@ -1,3 +1,3 @@
exports.index = function(req, res){
res.redirect('/users');
};
};

View File

@@ -4,6 +4,8 @@
var db = require('../../db');
exports.engine = 'hbs';
exports.before = function(req, res, next){
var id = req.params.user_id;
if (!id) return next();

View File

@@ -0,0 +1,25 @@
<!DOCTYPE html>
<html>
<head>
<link rel="stylesheet" href="/style.css">
<title>Edit {{user.name}}</title>
</head>
<body>
<h1>{{user.name}}</h1>
<form action="/user/{{user.id}}?_method=put" method="post">
<label for="user[name]">Name:
<input type="text" name="user[name]" value="{{user.name}}">
</label>
<input type="submit" name="submit" value="Update">
</form>
<form action="/user/{{user.id}}/pet" method="post">
<label for="pet[name]">Pet:
<input type="text" name="pet[name]" placeholder="Pet Name">
</label>
<input type="submit" name="submit" value="Add">
</form>
</body>
</html>

View File

@@ -1,11 +0,0 @@
link(rel='stylesheet', href='/style.css')
h1= user.name
form(action='/user/#{user.id}?_method=put', method='post')
label= 'Name: '
input(type='text', name='user[name]', value='#{user.name}')
input(type='submit', value='Update')
form(action='/user/#{user.id}/pet', method='post')
label= 'Pet: '
input(type='text', name='pet[name]', placeholder='Name')
input(type='submit', value='Add')

View File

@@ -0,0 +1,16 @@
<!DOCTYPE html>
<html>
<head>
<link rel="stylesheet" href="/style.css">
<title>Users</title>
</head>
<body>
<h1>Users</h1>
<p>Click a user below to view their pets.</p>
<ul>
{{#each users}}
<li><a href="/user/{{id}}">{{name}}</a></li>
{{/each}}
</ul>
</body>
</html>

View File

@@ -1,7 +0,0 @@
link(rel='stylesheet', href='/style.css')
h1 Users
p Click a user below to view their pets.
ul
each user in users
li
a(href='/user/#{user.id}')= user.name

View File

@@ -0,0 +1,29 @@
<!DOCTYPE html>
<html>
<head>
<link rel="stylesheet" href="/style.css">
<title>{{user.name}}</title>
</head>
<body>
<h1>{{user.name}} <a href="/user/{{user.id}}/edit">edit</a></h1>
{{#if hasMessages}}
<ul>
{{#each messages}}
<li>{{this}}</li>
{{/each}}
</ul>
{{/if}}
{{#if user.pets.length}}
<p>View {{user.name}}'s pets:</p>
<ul>
{{#each user.pets}}
<li><a href="/pet/{{id}}">{{name}}</a></li>
{{/each}}
</ul>
{{else}}
<p>No pets!</p>
{{/if}}
</body>
</html>

View File

@@ -1,17 +0,0 @@
link(rel='stylesheet', href='/style.css')
h1= user.name + ' '
a(href='/user/#{user.id}/edit') edit
if (hasMessages)
ul#messages
each msg in messages
li= msg
if (user.pets.length)
p View #{user.name}'s pets:
ul
each pet in user.pets
li
a(href='/pet/#{pet.id}')= pet.name
else
p No pets!

View File

@@ -11,4 +11,4 @@ var users = exports.users = [];
users.push({ name: 'TJ', pets: [pets[0], pets[1], pets[2]], id: 0 });
users.push({ name: 'Guillermo', pets: [pets[3]], id: 1 });
users.push({ name: 'Nathan', pets: [], id: 2 });
users.push({ name: 'Nathan', pets: [], id: 2 });

View File

@@ -6,16 +6,13 @@ var express = require('../..');
var logger = require('morgan');
var path = require('path');
var session = require('express-session');
var bodyParser = require('body-parser');
var methodOverride = require('method-override');
var app = module.exports = express();
// settings
// set our default template engine to "jade"
// which prevents the need for extensions
app.set('view engine', 'jade');
// set our default template engine to "ejs"
// which prevents the need for using file extensions
app.set('view engine', 'ejs');
// set views for error and 404 pages
app.set('views', path.join(__dirname, 'views'));
@@ -45,7 +42,7 @@ app.use(session({
}));
// parse request bodies (req.body)
app.use(bodyParser.urlencoded({ extended: true }));
app.use(express.urlencoded({ extended: true }))
// allow overriding methods in query (?_method=put)
app.use(methodOverride('_method'));

View File

@@ -0,0 +1,12 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>Not Found</title>
<link rel="stylesheet" href="/style.css">
</head>
<body>
<h1>404: Not Found</h1>
<p>Sorry we can't find <%= url %></p>
</body>
</html>

View File

@@ -1,3 +0,0 @@
link(rel='stylesheet', href='/style.css')
h1 404: Not Found
p Sorry we can't find #{url}

View File

@@ -0,0 +1,12 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>Internal Server Error</title>
<link rel="stylesheet" href="/style.css">
</head>
<body>
<h1>500: Internal Server Error</h1>
<p>Looks like something blew up!</p>
</body>
</html>

View File

@@ -1,3 +0,0 @@
link(rel='stylesheet', href='/style.css')
h1 500: Internal Server Error
p Looks like something blew up!

View File

@@ -1,4 +1,8 @@
// first:
// install redis first:
// https://redis.io/
// then:
// $ npm install redis online
// $ redis-server

View File

@@ -68,7 +68,7 @@ app.get('/users/:from-:to', function(req, res, next){
var from = req.params.from;
var to = req.params.to;
var names = users.map(function(user){ return user.name; });
res.send('users ' + names.slice(from, to).join(', '));
res.send('users ' + names.slice(from, to + 1).join(', '));
});
/* istanbul ignore next */

View File

@@ -75,7 +75,7 @@ app.resource('/users', User);
app.get('/', function(req, res){
res.send([
'<h1>Examples:</h1> <ul>'
'<h1>Examples:</h1> <ul>'
, '<li>GET /users</li>'
, '<li>GET /users/1</li>'
, '<li>GET /users/3</li>'

View File

@@ -7,7 +7,6 @@ var path = require('path');
var app = express();
var logger = require('morgan');
var cookieParser = require('cookie-parser');
var bodyParser = require('body-parser');
var methodOverride = require('method-override');
var site = require('./site');
var post = require('./post');
@@ -17,7 +16,7 @@ module.exports = app;
// Config
app.set('view engine', 'jade');
app.set('view engine', 'ejs');
app.set('views', path.join(__dirname, 'views'));
/* istanbul ignore next */
@@ -27,7 +26,7 @@ if (!module.parent) {
app.use(methodOverride('_method'));
app.use(cookieParser());
app.use(bodyParser.urlencoded({ extended: true }));
app.use(express.urlencoded({ extended: true }))
app.use(express.static(path.join(__dirname, 'public')));
// General

View File

@@ -1,3 +1,3 @@
exports.index = function(req, res){
res.render('index', { title: 'Route Separation Example' });
};
};

View File

@@ -0,0 +1,2 @@
</body>
</html>

View File

@@ -0,0 +1,8 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<title><%= title %></title>
<link rel="stylesheet" href="/style.css">
</head>
<body>

View File

@@ -0,0 +1,10 @@
<% include header %>
<h1><%= title %></h1>
<ul>
<li>Visit the <a href="/users">users</a> page.</li>
<li>Visit the <a href="/posts">posts</a> page.</li>
</ul>
<% include footer %>

View File

@@ -1,6 +0,0 @@
extends layout
block content
ul
li Visit the <a href="/users">users</a> page
li Visit the <a href="/posts">posts</a> page

View File

@@ -1,6 +0,0 @@
html
head
title= title
link(href="/style.css", rel="stylesheet")
body
block content

View File

@@ -0,0 +1,12 @@
<% include ../header %>
<h1>Posts</h1>
<dl id="posts">
<% posts.forEach(function(post) { %>
<dt><%= post.title %></dt>
<dd><%= post.body %></dd>
<% }) %>
</dl>
<% include ../footer %>

View File

@@ -1,8 +0,0 @@
extends ../layout
block content
h1 Posts
dl#posts
for post in posts
dt= post.title
dd= post.body

View File

@@ -0,0 +1,23 @@
<% include ../header %>
<h1>Editing <%= user.name %></h1>
<div id="user">
<form action="?_method=put", method="post">
<p>
Name:
<input type="text" value="<%= user.name %>" name="user[name]" />
</p>
<p>
Email:
<input type="email" value="<%= user.email %>" name="user[email]" />
</p>
<p>
<input type="submit" value="Save" />
</p>
</form>
</div>
<% include ../footer %>

View File

@@ -1,12 +0,0 @@
extends ../layout
block content
h1 Editing #{user.name}
#user
form(action="?_method=put", method="post")
p Name:
input(type="text", value= user.name, name="user[name]")
p Email:
input(type="text", value= user.email, name="user[email]")
p
input(type="submit", value="Save")

View File

@@ -0,0 +1,14 @@
<% include ../header %>
<h1><%= title %></h1>
<div id="users">
<% users.forEach(function(user, index) { %>
<li>
<a href="/user/<%= index %>"><%= user.name %></a>
<a href="/user/<%= index %>/edit">edit</a>
</li>
<% }) %>
</div>
<% include ../footer %>

View File

@@ -1,9 +0,0 @@
extends ../layout
block content
h1 Users
#users
for user, i in users
li
a(href="/user/#{i}")= user.name
a.edit(href="/user/#{i}/edit") edit

View File

@@ -0,0 +1,9 @@
<% include ../header %>
<h1><%= user.name %></h1>
<div id="user">
<p>Email: <%= user.email %></p>
</div>
<% include ../footer %>

View File

@@ -1,6 +0,0 @@
extends ../layout
block content
h1= user.name
#user
p Email: #{user.email}

View File

@@ -1,4 +1,8 @@
// first:
// install redis first:
// https://redis.io/
// then:
// $ npm install redis
// $ redis-server

View File

@@ -10,4 +10,4 @@ search.addEventListener('keyup', function(){
}
};
xhr.send();
}, false);
}, false);

View File

@@ -1,4 +1,8 @@
// first:
// install redis first:
// https://redis.io/
// then:
// $ npm install redis
// $ redis-server

View File

@@ -1 +1 @@
foo
foo

View File

@@ -2,7 +2,7 @@
* Module dependencies.
*/
var http = require('http');
var https = require('https');
var path = require('path');
var extname = path.extname;

View File

@@ -3,7 +3,6 @@
*/
var express = require('../../');
var http = require('http');
var GithubView = require('./github-view');
var md = require('marked').parse;

View File

@@ -3,11 +3,12 @@
*/
var express = require('../..');
var path = require('path');
var User = require('./user');
var app = express();
app.set('views', __dirname);
app.set('view engine', 'jade');
app.set('views', path.join(__dirname, 'views'));
app.set('view engine', 'ejs');
// filter ferrets only
@@ -25,7 +26,7 @@ app.get('/', function(req, res, next){
if (err) return next(err);
User.all(function(err, users){
if (err) return next(err);
res.render('user', {
res.render('index', {
title: 'Users',
count: count,
users: users.filter(ferrets)
@@ -59,7 +60,7 @@ function users(req, res, next) {
}
app.get('/middleware', count, users, function(req, res, next){
res.render('user', {
res.render('index', {
title: 'Users',
count: req.count,
users: req.users.filter(ferrets)
@@ -101,7 +102,7 @@ app.get('/middleware-locals', count2, users2, function(req, res, next){
// to pass to res.render(). If we have
// several routes related to users this
// can be a great productivity booster
res.render('user', { title: 'Users' });
res.render('index', { title: 'Users' });
});
// keep in mind that middleware may be placed anywhere

View File

@@ -1,12 +0,0 @@
doctype html
html
head
title= title
style.
body {
padding: 50px;
font: 16px Helvetica, Arial;
}
body
h2= title
block content

View File

@@ -1,8 +0,0 @@
extends layout
block content
for user in users
.user
h3= user.name
p #{user.name} is a #{user.age} year old #{user.species}.

View File

@@ -0,0 +1,19 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title><%= title %></title>
<style media="screen">
body {
padding: 50px;
font: 16px Helvetica, Arial;
}
</style>
</head>
<body>
<h2><%= title %></h2>
<% users.forEach(function(user) { %>
<li><strong><%= user.name %></strong> is a <% user.age %> year old <%= user.species %></li>
<% }); %>
</body>
</html>

View File

@@ -61,7 +61,7 @@ var users = [
];
var userRepos = {
tobi: [repos[0], repos[1]]
tobi: [repos[0], repos[1]]
, loki: [repos[1]]
, jane: [repos[2]]
};

View File

@@ -28,7 +28,7 @@ var deprecate = require('depd')('express');
var flatten = require('array-flatten');
var merge = require('utils-merge');
var resolve = require('path').resolve;
var setPrototyeOf = require('setprototypeof')
var setPrototypeOf = require('setprototypeof')
var slice = Array.prototype.slice;
/**
@@ -95,10 +95,10 @@ app.defaultConfiguration = function defaultConfiguration() {
}
// inherit protos
setPrototyeOf(this.request, parent.request)
setPrototyeOf(this.response, parent.response)
setPrototyeOf(this.engines, parent.engines)
setPrototyeOf(this.settings, parent.settings)
setPrototypeOf(this.request, parent.request)
setPrototypeOf(this.response, parent.response)
setPrototypeOf(this.engines, parent.engines)
setPrototypeOf(this.settings, parent.settings)
});
// setup locals
@@ -207,7 +207,7 @@ app.use = function use(fn) {
var fns = flatten(slice.call(arguments, offset));
if (fns.length === 0) {
throw new TypeError('app.use() requires middleware functions');
throw new TypeError('app.use() requires a middleware function')
}
// setup router
@@ -228,8 +228,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) {
setPrototyeOf(req, orig.request)
setPrototyeOf(res, orig.response)
setPrototypeOf(req, orig.request)
setPrototypeOf(res, orig.response)
next(err);
});
});
@@ -338,7 +338,7 @@ app.param = function param(name, fn) {
* Assign `setting` to `val`, or return `setting`'s value.
*
* app.set('foo', 'bar');
* app.get('foo');
* app.set('foo');
* // => "bar"
*
* Mounted servers inherit their parent server's settings.

View File

@@ -12,6 +12,7 @@
* Module dependencies.
*/
var bodyParser = require('body-parser')
var EventEmitter = require('events').EventEmitter;
var mixin = require('merge-descriptors');
var proto = require('./application');
@@ -74,16 +75,16 @@ exports.Router = Router;
* Expose middleware
*/
exports.json = bodyParser.json
exports.query = require('./middleware/query');
exports.static = require('serve-static');
exports.urlencoded = bodyParser.urlencoded
/**
* Replace removed middleware with an appropriate error message.
*/
[
'json',
'urlencoded',
;[
'bodyParser',
'compress',
'cookieSession',

View File

@@ -13,7 +13,7 @@
* @private
*/
var setPrototyeOf = require('setprototypeof')
var setPrototypeOf = require('setprototypeof')
/**
* Initialization middleware, exposing the
@@ -32,8 +32,8 @@ exports.init = function(app){
res.req = req;
req.next = next;
setPrototyeOf(req, app.request)
setPrototyeOf(res, app.response)
setPrototypeOf(req, app.request)
setPrototypeOf(res, app.response)
res.locals = res.locals || Object.create(null);

View File

@@ -12,6 +12,7 @@
* Module dependencies.
*/
var merge = require('utils-merge')
var parseUrl = require('parseurl');
var qs = require('qs');
@@ -22,7 +23,7 @@ var qs = require('qs');
*/
module.exports = function query(options) {
var opts = Object.create(options || null);
var opts = merge({}, options)
var queryparse = qs.parse;
if (typeof options === 'function') {

View File

@@ -315,8 +315,12 @@ defineGetter(req, 'protocol', function protocol(){
// Note: X-Forwarded-Proto is normally only ever a
// single value, but this is to be safe.
proto = this.get('X-Forwarded-Proto') || proto;
return proto.split(/\s*,\s*/)[0];
var header = this.get('X-Forwarded-Proto') || proto
var index = header.indexOf(',')
return index !== -1
? header.substring(0, index).trim()
: header.trim()
});
/**

View File

@@ -12,6 +12,7 @@
* @private
*/
var Buffer = require('safe-buffer').Buffer
var contentDisposition = require('content-disposition');
var deprecate = require('depd')('express');
var encodeUrl = require('encodeurl');
@@ -95,7 +96,7 @@ res.links = function(links){
*
* Examples:
*
* res.send(new Buffer('wahoo'));
* res.send(Buffer.from('wahoo'));
* res.send({ some: 'json' });
* res.send('<p>some html</p>');
*
@@ -106,7 +107,6 @@ res.links = function(links){
res.send = function send(body) {
var chunk = body;
var encoding;
var len;
var req = this.req;
var type;
@@ -171,23 +171,33 @@ res.send = function send(body) {
}
}
// determine if ETag should be generated
var etagFn = app.get('etag fn')
var generateETag = !this.get('ETag') && typeof etagFn === 'function'
// populate Content-Length
var len
if (chunk !== undefined) {
if (!Buffer.isBuffer(chunk)) {
// convert chunk to Buffer; saves later double conversions
chunk = new Buffer(chunk, encoding);
if (Buffer.isBuffer(chunk)) {
// get length of Buffer
len = chunk.length
} else if (!generateETag && chunk.length < 1000) {
// just calculate length when no ETag + small chunk
len = Buffer.byteLength(chunk, encoding)
} else {
// convert chunk to Buffer and calculate
chunk = Buffer.from(chunk, encoding)
encoding = undefined;
len = chunk.length
}
len = chunk.length;
this.set('Content-Length', len);
}
// populate ETag
var etag;
var generateETag = len !== undefined && app.get('etag fn');
if (typeof generateETag === 'function' && !this.get('ETag')) {
if ((etag = generateETag(chunk, encoding))) {
if (generateETag && len !== undefined) {
if ((etag = etagFn(chunk, encoding))) {
this.set('ETag', etag);
}
}
@@ -244,9 +254,10 @@ res.json = function json(obj) {
// 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);
var body = stringify(val, replacer, spaces, escape)
// content-type
if (!this.get('Content-Type')) {
@@ -286,9 +297,10 @@ res.jsonp = function jsonp(obj) {
// 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);
var body = stringify(val, replacer, spaces, escape)
var callback = this.req.query[app.get('jsonp callback name')];
// content-type
@@ -304,7 +316,6 @@ res.jsonp = function jsonp(obj) {
// jsonp
if (typeof callback === 'string' && callback.length !== 0) {
this.charset = 'utf-8';
this.set('X-Content-Type-Options', 'nosniff');
this.set('Content-Type', 'text/javascript');
@@ -506,19 +517,29 @@ res.sendfile = deprecate.function(res.sendfile,
* when the data transfer is complete, or when an error has
* ocurred. Be sure to check `res.headersSent` if you plan to respond.
*
* This method uses `res.sendfile()`.
* Optionally providing an `options` object to use with `res.sendFile()`.
* This function will set the `Content-Disposition` header, overriding
* any `Content-Disposition` header passed as header options in order
* to set the attachment and filename.
*
* This method uses `res.sendFile()`.
*
* @public
*/
res.download = function download(path, filename, callback) {
res.download = function download (path, filename, options, callback) {
var done = callback;
var name = filename;
var opts = options || null
// support function as second arg
// support function as second or third arg
if (typeof filename === 'function') {
done = filename;
name = null;
opts = null
} else if (typeof options === 'function') {
done = options
opts = null
}
// set Content-Disposition when file is sent
@@ -526,10 +547,26 @@ res.download = function download(path, filename, callback) {
'Content-Disposition': contentDisposition(name || path)
};
// merge user-provided headers
if (opts && opts.headers) {
var keys = Object.keys(opts.headers)
for (var i = 0; i < keys.length; i++) {
var key = keys[i]
if (key.toLowerCase() !== 'content-disposition') {
headers[key] = opts.headers[key]
}
}
}
// merge user-provided options
opts = Object.create(opts)
opts.headers = headers
// Resolve the full path for sendFile
var fullPath = resolve(path);
return this.sendFile(fullPath, { headers: headers }, done);
// send file
return this.sendFile(fullPath, opts, done)
};
/**
@@ -717,9 +754,14 @@ res.header = function header(field, val) {
: String(val);
// add charset to content-type
if (field.toLowerCase() === 'content-type' && !charsetRegExp.test(value)) {
var charset = mime.charsets.lookup(value.split(';')[0]);
if (charset) value += '; charset=' + charset.toLowerCase();
if (field.toLowerCase() === 'content-type') {
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();
}
}
this.setHeader(field, value);
@@ -777,7 +819,7 @@ res.clearCookie = function clearCookie(name, options) {
*
* @param {String} name
* @param {String|Object} value
* @param {Options} options
* @param {Object} [options]
* @return {ServerResponse} for chaining
* @public
*/
@@ -1058,14 +1100,38 @@ function sendfile(res, file, options, callback) {
}
/**
* Stringify JSON, like JSON.stringify, but v8 optimized.
* Stringify JSON, like JSON.stringify, but v8 optimized, with the
* ability to escape characters that can trigger HTML sniffing.
*
* @param {*} value
* @param {function} replaces
* @param {number} spaces
* @param {boolean} escape
* @returns {string}
* @private
*/
function stringify(value, replacer, spaces) {
function stringify (value, replacer, spaces, escape) {
// v8 checks arguments.length for optimizing simple call
// https://bugs.chromium.org/p/v8/issues/detail?id=4730
return replacer || spaces
var json = replacer || spaces
? JSON.stringify(value, replacer, spaces)
: JSON.stringify(value);
if (escape) {
json = json.replace(/[<>&]/g, function (c) {
switch (c.charCodeAt(0)) {
case 0x3c:
return '\\u003c'
case 0x3e:
return '\\u003e'
case 0x26:
return '\\u0026'
default:
return c
}
})
}
return json
}

View File

@@ -448,14 +448,14 @@ proto.use = function use(fn) {
var callbacks = flatten(slice.call(arguments, offset));
if (callbacks.length === 0) {
throw new TypeError('Router.use() requires middleware functions');
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 middleware function but got a ' + gettype(fn));
throw new TypeError('Router.use() requires a middleware function but got a ' + gettype(fn))
}
// add the middleware

View File

@@ -175,7 +175,7 @@ Route.prototype.all = function all() {
if (typeof handle !== 'function') {
var type = toString.call(handle);
var msg = 'Route.all() requires callback functions but got a ' + type;
var msg = 'Route.all() requires a callback function but got a ' + type
throw new TypeError(msg);
}
@@ -198,7 +198,7 @@ methods.forEach(function(method){
if (typeof handle !== 'function') {
var type = toString.call(handle);
var msg = 'Route.' + method + '() requires callback functions but got a ' + type;
var msg = 'Route.' + method + '() requires a callback function but got a ' + type
throw new Error(msg);
}

View File

@@ -12,12 +12,12 @@
* @api private
*/
var Buffer = require('safe-buffer').Buffer
var contentDisposition = require('content-disposition');
var contentType = require('content-type');
var deprecate = require('depd')('express');
var flatten = require('array-flatten');
var mime = require('send').mime;
var basename = require('path').basename;
var etag = require('etag');
var proxyaddr = require('proxy-addr');
var qs = require('qs');
@@ -32,13 +32,7 @@ var querystring = require('querystring');
* @api private
*/
exports.etag = function (body, encoding) {
var buf = !Buffer.isBuffer(body)
? new Buffer(body, encoding)
: body;
return etag(buf, {weak: false});
};
exports.etag = createETagGenerator({ weak: false })
/**
* Return weak ETag for `body`.
@@ -49,13 +43,7 @@ exports.etag = function (body, encoding) {
* @api private
*/
exports.wetag = function wetag(body, encoding){
var buf = !Buffer.isBuffer(body)
? new Buffer(body, encoding)
: body;
return etag(buf, {weak: true});
};
exports.wetag = createETagGenerator({ weak: true })
/**
* Check if `path` looks absolute.
@@ -274,6 +262,25 @@ exports.setCharset = function setCharset(type, charset) {
return contentType.format(parsed);
};
/**
* Create an ETag generator function, generating ETags with
* the given options.
*
* @param {object} options
* @return {function}
* @private
*/
function createETagGenerator (options) {
return function generateETag (body, encoding) {
var buf = !Buffer.isBuffer(body)
? Buffer.from(body, encoding)
: body
return etag(buf, options)
}
}
/**
* Parse an extended query string with qs.
*

View File

@@ -16,7 +16,6 @@
var debug = require('debug')('express:view');
var path = require('path');
var fs = require('fs');
var utils = require('./utils');
/**
* Module variables.
@@ -77,7 +76,15 @@ function View(name, options) {
// load engine
var mod = this.ext.substr(1)
debug('require "%s"', mod)
opts.engines[this.ext] = require(mod).__express
// default engine export
var fn = require(mod).__express
if (typeof fn !== 'function') {
throw new Error('Module "' + mod + '" does not provide a view engine.')
}
opts.engines[this.ext] = fn
}
// store loaded engine

View File

@@ -1,7 +1,7 @@
{
"name": "express",
"description": "Fast, unopinionated, minimalist web framework",
"version": "4.15.2",
"version": "4.16.2",
"author": "TJ Holowaychuk <tj@vision-media.ca>",
"contributors": [
"Aaron Heckmann <aaron.heckmann+github@gmail.com>",
@@ -27,53 +27,55 @@
"api"
],
"dependencies": {
"accepts": "~1.3.3",
"accepts": "~1.3.4",
"array-flatten": "1.1.1",
"body-parser": "1.18.2",
"content-disposition": "0.5.2",
"content-type": "~1.0.2",
"content-type": "~1.0.4",
"cookie": "0.3.1",
"cookie-signature": "1.0.6",
"debug": "2.6.1",
"depd": "~1.1.0",
"debug": "2.6.9",
"depd": "~1.1.1",
"encodeurl": "~1.0.1",
"escape-html": "~1.0.3",
"etag": "~1.8.0",
"finalhandler": "~1.0.0",
"fresh": "0.5.0",
"etag": "~1.8.1",
"finalhandler": "1.1.0",
"fresh": "0.5.2",
"merge-descriptors": "1.0.1",
"methods": "~1.1.2",
"on-finished": "~2.3.0",
"parseurl": "~1.3.1",
"parseurl": "~1.3.2",
"path-to-regexp": "0.1.7",
"proxy-addr": "~1.1.3",
"qs": "6.4.0",
"proxy-addr": "~2.0.2",
"qs": "6.5.1",
"range-parser": "~1.2.0",
"send": "0.15.1",
"serve-static": "1.12.1",
"setprototypeof": "1.0.3",
"safe-buffer": "5.1.1",
"send": "0.16.1",
"serve-static": "1.13.1",
"setprototypeof": "1.1.0",
"statuses": "~1.3.1",
"type-is": "~1.6.14",
"utils-merge": "1.0.0",
"vary": "~1.1.0"
"type-is": "~1.6.15",
"utils-merge": "1.0.1",
"vary": "~1.1.2"
},
"devDependencies": {
"after": "0.8.2",
"body-parser": "1.17.1",
"cookie-parser": "~1.4.3",
"ejs": "2.5.6",
"express-session": "1.15.1",
"cookie-session": "1.3.2",
"ejs": "2.5.7",
"eslint": "2.13.1",
"express-session": "1.15.6",
"hbs": "4.0.1",
"istanbul": "0.4.5",
"marked": "0.3.6",
"method-override": "2.3.7",
"mocha": "3.2.0",
"morgan": "1.8.1",
"method-override": "2.3.10",
"mocha": "3.5.3",
"morgan": "1.9.0",
"multiparty": "4.1.3",
"pbkdf2-password": "1.2.1",
"should": "11.2.0",
"should": "13.1.0",
"supertest": "1.2.0",
"connect-redis": "~2.4.1",
"cookie-session": "~1.2.0",
"jade": "~1.11.0",
"vhost": "~3.0.2"
},
"engines": {
@@ -87,9 +89,10 @@
"lib/"
],
"scripts": {
"test": "mocha --require test/support/env --reporter spec --bail --check-leaks test/ test/acceptance/",
"test-ci": "istanbul cover node_modules/mocha/bin/_mocha --report lcovonly -- --require test/support/env --reporter spec --check-leaks test/ test/acceptance/",
"test-cov": "istanbul cover node_modules/mocha/bin/_mocha -- --require test/support/env --reporter dot --check-leaks test/ test/acceptance/",
"test-tap": "mocha --require test/support/env --reporter tap --check-leaks test/ test/acceptance/"
"lint": "eslint .",
"test": "mocha --require test/support/env --reporter spec --bail --check-leaks --no-exit test/ test/acceptance/",
"test-ci": "istanbul cover node_modules/mocha/bin/_mocha --report lcovonly -- --require test/support/env --reporter spec --check-leaks --no-exit test/ test/acceptance/",
"test-cov": "istanbul cover node_modules/mocha/bin/_mocha -- --require test/support/env --reporter dot --check-leaks --no-exit test/ test/acceptance/",
"test-tap": "mocha --require test/support/env --reporter tap --check-leaks --no-exit test/ test/acceptance/"
}
}

View File

@@ -4,7 +4,6 @@ var should = require('should');
var express = require('../')
, Route = express.Route
, methods = require('methods')
, assert = require('assert');
describe('Route', function(){
it('should work without handlers', function(done) {
@@ -25,7 +24,7 @@ describe('Route', function(){
route.dispatch(req, {}, function (err) {
if (err) return done(err);
should(req.called).be.ok;
should(req.called).be.ok()
done();
});
})
@@ -84,7 +83,7 @@ describe('Route', function(){
route.dispatch(req, {}, function (err) {
if (err) return done(err);
should(req.called).be.ok;
should(req.called).be.ok()
done();
});
})
@@ -104,7 +103,7 @@ describe('Route', function(){
route.dispatch(req, {}, function (err) {
if (err) return done(err);
should(req.called).be.true;
should(req.called).be.true()
done();
});
})
@@ -156,7 +155,7 @@ describe('Route', function(){
});
route.dispatch(req, {}, function (err) {
should(err).be.ok;
should(err).be.ok()
should(err.message).equal('foobar');
req.order.should.equal('a');
done();
@@ -182,7 +181,7 @@ describe('Route', function(){
});
route.dispatch(req, {}, function (err) {
should(err).be.ok;
should(err).be.ok()
should(err.message).equal('foobar');
req.order.should.equal('a');
done();
@@ -222,7 +221,7 @@ describe('Route', function(){
});
route.dispatch(req, {}, function(err){
should(err).be.ok;
should(err).be.ok()
err.message.should.equal('boom!');
done();
});
@@ -234,7 +233,7 @@ describe('Route', function(){
route.all(function(err, req, res, next){
// this should not execute
true.should.be.false;
true.should.be.false()
});
route.dispatch(req, {}, done);

View File

@@ -47,7 +47,7 @@ describe('Router', function(){
var router = new Router();
router.use(function (req, res) {
false.should.be.true;
false.should.be.true()
});
router.handle({ url: '', method: 'GET' }, {}, done);
@@ -368,17 +368,29 @@ describe('Router', function(){
})
describe('.use', function() {
it('should require arguments', function(){
var router = new Router();
router.use.bind(router).should.throw(/requires middleware function/)
it('should require middleware', function () {
var router = new Router()
assert.throws(function () { router.use('/') }, /requires a middleware function/)
})
it('should not accept non-functions', function(){
var router = new Router();
router.use.bind(router, '/', 'hello').should.throw(/requires middleware function.*string/)
router.use.bind(router, '/', 5).should.throw(/requires middleware function.*number/)
router.use.bind(router, '/', null).should.throw(/requires middleware function.*Null/)
router.use.bind(router, '/', new Date()).should.throw(/requires middleware function.*Date/)
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/)
})
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/)
})
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/)
})
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/)
})
it('should be called for any URL', function (done) {

View File

@@ -7,7 +7,7 @@ describe('cookie-sessions', function () {
it('should display no views', function (done) {
request(app)
.get('/')
.expect(200, 'viewed 0 times\n', done)
.expect(200, 'viewed 1 times\n', done)
})
it('should set a session cookie', function (done) {
@@ -20,12 +20,12 @@ describe('cookie-sessions', function () {
it('should display 1 view on revisit', function (done) {
request(app)
.get('/')
.expect(200, 'viewed 0 times\n', function (err, res) {
.expect(200, 'viewed 1 times\n', function (err, res) {
if (err) return done(err)
request(app)
.get('/')
.set('Cookie', getCookies(res))
.expect(200, 'viewed 1 times\n', done)
.expect(200, 'viewed 2 times\n', done)
})
})
})

View File

@@ -99,4 +99,4 @@ describe('error-pages', function(){
})
})
})
})
})

View File

@@ -26,4 +26,4 @@ describe('error', function(){
.expect(404,done)
})
})
})
})

View File

@@ -29,8 +29,8 @@ describe('params', function(){
describe('GET /users/0-2', function(){
it('should respond with three users', function(done){
request(app)
.get('/users/0-2')
.expect(/users tj, tobi/,done)
.get('/users/0-2')
.expect(/users tj, tobi, loki/, done)
})
})

View File

@@ -42,4 +42,4 @@ describe('route-map', function(){
.expect('delete 12\'s pet 2', done);
})
})
})
})

View File

@@ -47,7 +47,7 @@ describe('app', function(){
done();
})
})
it('should work "view engine" setting', function(done){
var app = express();
@@ -62,7 +62,7 @@ describe('app', function(){
done();
})
})
it('should work "view engine" with leading "."', function(done){
var app = express();

View File

@@ -86,7 +86,7 @@ describe('in development', function(){
it('should disable "view cache"', function(){
process.env.NODE_ENV = 'development';
var app = express();
app.enabled('view cache').should.be.false;
app.enabled('view cache').should.be.false()
process.env.NODE_ENV = 'test';
})
})
@@ -95,7 +95,7 @@ describe('in production', function(){
it('should enable "view cache"', function(){
process.env.NODE_ENV = 'production';
var app = express();
app.enabled('view cache').should.be.true;
app.enabled('view cache').should.be.true()
process.env.NODE_ENV = 'test';
})
})

View File

@@ -1,6 +1,5 @@
var express = require('../')
, request = require('supertest');
describe('app.listen()', function(){
it('should wrap with an HTTP server', function(done){

View File

@@ -1,6 +1,5 @@
var express = require('../')
, request = require('supertest');
describe('app', function(){
describe('.locals(obj)', function(){

View File

@@ -57,13 +57,13 @@ describe('app', function(){
app.get('/post/:id', function(req, res){
var id = req.params.id;
id.should.be.a.Number;
id.should.be.a.Number()
res.send('' + id);
});
app.get('/user/:uid', function(req, res){
var id = req.params.id;
id.should.be.a.Number;
id.should.be.a.Number()
res.send('' + id);
});
@@ -91,7 +91,7 @@ describe('app', function(){
app.get('/user/:id', function(req, res){
var id = req.params.id;
id.should.be.a.Number;
id.should.be.a.Number()
res.send('' + id);
});

View File

@@ -72,7 +72,7 @@ describe('app', function(){
app.set('view', View);
app.render('something', function(err, str){
err.should.be.ok;
err.should.be.ok()
err.message.should.equal('err!');
done();
})
@@ -97,12 +97,10 @@ describe('app', function(){
app.set('views', path.join(__dirname, 'fixtures'))
app.render('user.tmpl', function (err, str) {
// nextTick to prevent cyclic
process.nextTick(function(){
err.message.should.match(/Cannot read property '[^']+' of undefined/);
done();
});
app.render('user.tmpl', function (err) {
assert.ok(err)
assert.equal(err.name, 'RenderError')
done()
})
})
})

View File

@@ -39,7 +39,6 @@ describe('app.router', function(){
it('should include ' + method.toUpperCase(), function(done){
var app = express();
var calls = [];
app[method]('/foo', function(req, res){
if ('head' == method) {

View File

@@ -44,10 +44,10 @@ describe('app', function(){
d = true;
next();
}, function(req, res){
a.should.be.false;
b.should.be.true;
c.should.be.true;
d.should.be.false;
a.should.be.false()
b.should.be.true()
c.should.be.true()
d.should.be.false()
res.send(204);
});

View File

@@ -1,5 +1,6 @@
var after = require('after');
var assert = require('assert')
var express = require('..');
var request = require('supertest');
@@ -253,17 +254,29 @@ describe('app', function(){
})
describe('.use(path, middleware)', function(){
it('should reject missing functions', function () {
var app = express();
app.use.bind(app, '/').should.throw(/requires middleware function/);
it('should require middleware', function () {
var app = express()
assert.throws(function () { app.use('/') }, /requires a middleware function/)
})
it('should reject non-functions as middleware', function () {
var app = express();
app.use.bind(app, '/', 'hi').should.throw(/requires middleware function.*string/);
app.use.bind(app, '/', 5).should.throw(/requires middleware function.*number/);
app.use.bind(app, '/', null).should.throw(/requires middleware function.*Null/);
app.use.bind(app, '/', new Date()).should.throw(/requires middleware function.*Date/);
it('should reject string as middleware', function () {
var app = express()
assert.throws(function () { app.use('/', 'foo') }, /requires a middleware function but got a string/)
})
it('should reject number as middleware', function () {
var app = express()
assert.throws(function () { app.use('/', 42) }, /requires a middleware function but got a number/)
})
it('should reject null as middleware', function () {
var app = express()
assert.throws(function () { app.use('/', null) }, /requires a middleware function but got a Null/)
})
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/)
})
it('should strip path from req.url', function (done) {

View File

@@ -49,7 +49,7 @@ describe('config', function () {
var app = express();
assert.strictEqual(app.get('foo'), undefined);
})
it('should otherwise return the value', function(){
var app = express();
app.set('foo', 'bar');
@@ -125,7 +125,7 @@ describe('config', function () {
assert.strictEqual(app.get('tobi'), true);
})
})
describe('.disable()', function(){
it('should set the value to false', function(){
var app = express();
@@ -133,26 +133,26 @@ describe('config', function () {
assert.strictEqual(app.get('tobi'), false);
})
})
describe('.enabled()', function(){
it('should default to false', function(){
var app = express();
assert.strictEqual(app.enabled('foo'), false);
})
it('should return true when set', function(){
var app = express();
app.set('foo', 'bar');
assert.strictEqual(app.enabled('foo'), true);
})
})
describe('.disabled()', function(){
it('should default to true', function(){
var app = express();
assert.strictEqual(app.disabled('foo'), true);
})
it('should return false when set', function(){
var app = express();
app.set('foo', 'bar');

View File

@@ -5,19 +5,19 @@ var should = require('should');
describe('exports', function(){
it('should expose Router', function(){
express.Router.should.be.a.Function;
express.Router.should.be.a.Function()
})
it('should expose the application prototype', function(){
express.application.set.should.be.a.Function;
express.application.set.should.be.a.Function()
})
it('should expose the request prototype', function(){
express.request.accepts.should.be.a.Function;
express.request.accepts.should.be.a.Function()
})
it('should expose the response prototype', function(){
express.response.send.should.be.a.Function;
express.response.send.should.be.a.Function()
})
it('should permit modifying the .application prototype', function(){

0
test/fixtures/broken.send vendored Normal file
View File

View File

@@ -28,7 +28,7 @@ describe('middleware', function(){
});
});
request(app.listen())
request(app)
.get('/')
.set('Content-Type', 'application/json')
.send('{"foo":"bar"}')

View File

@@ -8,8 +8,8 @@ describe('req', function(){
var app = express();
app.use(function(req, res){
req.acceptsEncoding('gzip').should.be.ok;
req.acceptsEncoding('deflate').should.be.ok;
req.acceptsEncoding('gzip').should.be.ok()
req.acceptsEncoding('deflate').should.be.ok()
res.end();
});
@@ -23,7 +23,7 @@ describe('req', function(){
var app = express();
app.use(function(req, res){
req.acceptsEncoding('bogus').should.not.be.ok;
req.acceptsEncoding('bogus').should.not.be.ok()
res.end();
});

View File

@@ -8,8 +8,8 @@ describe('req', function(){
var app = express();
app.use(function(req, res){
req.acceptsEncodings('gzip').should.be.ok;
req.acceptsEncodings('deflate').should.be.ok;
req.acceptsEncodings('gzip').should.be.ok()
req.acceptsEncodings('deflate').should.be.ok()
res.end();
});
@@ -23,7 +23,7 @@ describe('req', function(){
var app = express();
app.use(function(req, res){
req.acceptsEncodings('bogus').should.not.be.ok;
req.acceptsEncodings('bogus').should.not.be.ok()
res.end();
});

View File

@@ -8,8 +8,8 @@ describe('req', function(){
var app = express();
app.use(function(req, res){
req.acceptsLanguage('en-us').should.be.ok;
req.acceptsLanguage('en').should.be.ok;
req.acceptsLanguage('en-us').should.be.ok()
req.acceptsLanguage('en').should.be.ok()
res.end();
});
@@ -23,7 +23,7 @@ describe('req', function(){
var app = express();
app.use(function(req, res){
req.acceptsLanguage('es').should.not.be.ok;
req.acceptsLanguage('es').should.not.be.ok()
res.end();
});
@@ -38,9 +38,9 @@ describe('req', function(){
var app = express();
app.use(function(req, res){
req.acceptsLanguage('en').should.be.ok;
req.acceptsLanguage('es').should.be.ok;
req.acceptsLanguage('jp').should.be.ok;
req.acceptsLanguage('en').should.be.ok()
req.acceptsLanguage('es').should.be.ok()
req.acceptsLanguage('jp').should.be.ok()
res.end();
});

View File

@@ -8,8 +8,8 @@ describe('req', function(){
var app = express();
app.use(function(req, res){
req.acceptsLanguages('en-us').should.be.ok;
req.acceptsLanguages('en').should.be.ok;
req.acceptsLanguages('en-us').should.be.ok()
req.acceptsLanguages('en').should.be.ok()
res.end();
});
@@ -23,7 +23,7 @@ describe('req', function(){
var app = express();
app.use(function(req, res){
req.acceptsLanguages('es').should.not.be.ok;
req.acceptsLanguages('es').should.not.be.ok()
res.end();
});
@@ -38,9 +38,9 @@ describe('req', function(){
var app = express();
app.use(function(req, res){
req.acceptsLanguages('en').should.be.ok;
req.acceptsLanguages('es').should.be.ok;
req.acceptsLanguages('jp').should.be.ok;
req.acceptsLanguages('en').should.be.ok()
req.acceptsLanguages('es').should.be.ok()
req.acceptsLanguages('jp').should.be.ok()
res.end();
});

View File

@@ -1,7 +1,6 @@
var express = require('../')
, request = require('supertest')
, assert = require('assert');
describe('req', function(){
describe('.host', function(){

View File

@@ -1,7 +1,6 @@
var express = require('../')
, request = require('supertest')
, assert = require('assert');
describe('req', function(){
describe('.hostname', function(){

View File

@@ -1,7 +1,6 @@
var express = require('../')
, request = require('supertest')
, bodyParser = require('body-parser')
describe('req', function(){
describe('.param(name, default)', function(){
@@ -34,7 +33,7 @@ describe('req', function(){
it('should check req.body', function(done){
var app = express();
app.use(bodyParser.json());
app.use(express.json())
app.use(function(req, res){
res.end(req.param('name'));

View File

@@ -1,5 +1,4 @@
var assert = require('assert');
var express = require('..');
var request = require('supertest')

View File

@@ -8,7 +8,7 @@ describe('req', function(){
var app = express();
app.use(function(req, res){
req.xhr.should.be.true;
req.xhr.should.be.true()
res.end();
});
@@ -25,7 +25,7 @@ describe('req', function(){
var app = express();
app.use(function(req, res){
req.xhr.should.be.true;
req.xhr.should.be.true()
res.end();
});
@@ -42,7 +42,7 @@ describe('req', function(){
var app = express();
app.use(function(req, res){
req.xhr.should.be.false;
req.xhr.should.be.false()
res.end();
});
@@ -59,7 +59,7 @@ describe('req', function(){
var app = express();
app.use(function(req, res){
req.xhr.should.be.false;
req.xhr.should.be.false()
res.end();
});

View File

@@ -1,4 +1,5 @@
var Buffer = require('safe-buffer').Buffer
var express = require('../')
, request = require('supertest');
@@ -36,7 +37,7 @@ describe('res', function(){
app.use(function(req, res){
res.attachment('/path/to/image.png');
res.send(new Buffer(4));
res.send(Buffer.alloc(4, '.'))
});
request(app)

Some files were not shown because too many files have changed in this diff Show More