mirror of
https://github.com/expressjs/express.git
synced 2026-02-26 08:45:36 +00:00
Compare commits
192 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
6c8bcd5c4e | ||
|
|
95e63ec287 | ||
|
|
ebca5887cc | ||
|
|
8535d3a990 | ||
|
|
13184c4379 | ||
|
|
eaba4eeb70 | ||
|
|
28c6952d1c | ||
|
|
01e3530a31 | ||
|
|
77c83d0c57 | ||
|
|
a12ae729bd | ||
|
|
d53a0cd91e | ||
|
|
88dfd36eaa | ||
|
|
5759b3e9f5 | ||
|
|
c939a771c0 | ||
|
|
af1043844f | ||
|
|
dd763ec5b8 | ||
|
|
9c2c21aaaf | ||
|
|
366000184f | ||
|
|
4d1ee23f84 | ||
|
|
0e5613363f | ||
|
|
7a7f18c20b | ||
|
|
b766aad112 | ||
|
|
7488e27609 | ||
|
|
bc9d854763 | ||
|
|
2e20a85810 | ||
|
|
a706408208 | ||
|
|
6d39d0f8a8 | ||
|
|
159ea67713 | ||
|
|
33959ed350 | ||
|
|
be478d348c | ||
|
|
9f292d873e | ||
|
|
ef3e95ca73 | ||
|
|
f45bd632df | ||
|
|
cc18da5cdf | ||
|
|
5603f86edd | ||
|
|
43e2cd79cb | ||
|
|
653270bb43 | ||
|
|
734bdf5ca1 | ||
|
|
341c1919d9 | ||
|
|
b09afad7b1 | ||
|
|
0e0b259556 | ||
|
|
63286e1192 | ||
|
|
c00f2f8596 | ||
|
|
f29399c4e1 | ||
|
|
f6ac068ab0 | ||
|
|
7eb65eeca2 | ||
|
|
178fe15091 | ||
|
|
381f278d0a | ||
|
|
534fa181c6 | ||
|
|
80847d8c82 | ||
|
|
4b1b8e420f | ||
|
|
70767b19ac | ||
|
|
7d277c1c15 | ||
|
|
fa1fcd9fec | ||
|
|
2de6514b4b | ||
|
|
d07c06363f | ||
|
|
4e97533fd2 | ||
|
|
d7d6219a1e | ||
|
|
9b18461bbc | ||
|
|
b77aa38c98 | ||
|
|
cbb251377e | ||
|
|
d6ed469de3 | ||
|
|
49284c236b | ||
|
|
be18487f7d | ||
|
|
094ff11949 | ||
|
|
b97f6eb506 | ||
|
|
3d188fe13e | ||
|
|
8327708ec2 | ||
|
|
c8640b3465 | ||
|
|
3ce5f9b493 | ||
|
|
4d032cda05 | ||
|
|
4127ba10b0 | ||
|
|
0299bee8fa | ||
|
|
6a581c9961 | ||
|
|
0b12cc0cac | ||
|
|
fdd0ccabe8 | ||
|
|
8c36eab679 | ||
|
|
5c145b5490 | ||
|
|
d7bef52591 | ||
|
|
1576a95e87 | ||
|
|
7f92fe66e0 | ||
|
|
f13f4652da | ||
|
|
059c068c7b | ||
|
|
49947f1476 | ||
|
|
0dddd772c0 | ||
|
|
0f87c6f392 | ||
|
|
7119f2b16d | ||
|
|
a57efea173 | ||
|
|
4a4ca7347a | ||
|
|
570f60d36e | ||
|
|
d13e613584 | ||
|
|
9204e1f42a | ||
|
|
ddac571fdf | ||
|
|
982d24b475 | ||
|
|
ea427c1bb4 | ||
|
|
0bd6c311cf | ||
|
|
7f606ebf29 | ||
|
|
c652cf7eed | ||
|
|
19fd6f85b0 | ||
|
|
b6c5b0511f | ||
|
|
0e42a37edd | ||
|
|
b24ed15878 | ||
|
|
15590d75b2 | ||
|
|
e8b471ff4f | ||
|
|
767db01b79 | ||
|
|
696e150f0a | ||
|
|
819265c7ae | ||
|
|
baf8b14a71 | ||
|
|
06e7685d65 | ||
|
|
9f4968aaa3 | ||
|
|
afea3c0ae8 | ||
|
|
edaabe66cf | ||
|
|
f724730e1a | ||
|
|
e49d0dc9e3 | ||
|
|
e7a3fbaf48 | ||
|
|
928952e7f0 | ||
|
|
a28b7a85cf | ||
|
|
3fc8dc54ee | ||
|
|
0d77305a1a | ||
|
|
323c185079 | ||
|
|
1d0da9036b | ||
|
|
683ba1cd75 | ||
|
|
e4ff5281c9 | ||
|
|
7414a1f463 | ||
|
|
916c53737d | ||
|
|
b2382a7336 | ||
|
|
f684a64df7 | ||
|
|
5d03d0eac8 | ||
|
|
544c6665f5 | ||
|
|
cf8005e63f | ||
|
|
25ef8425d2 | ||
|
|
577cc1d1a0 | ||
|
|
3c87a6aede | ||
|
|
7c1f90bf16 | ||
|
|
7bcf5f5085 | ||
|
|
abe0ffa311 | ||
|
|
b601d64203 | ||
|
|
f381f2d9b6 | ||
|
|
12507cfcd0 | ||
|
|
185e327e29 | ||
|
|
c468f5ff20 | ||
|
|
9bb47fba30 | ||
|
|
78d489d730 | ||
|
|
8ffb9f9477 | ||
|
|
9cb147370e | ||
|
|
75422c16bf | ||
|
|
e66667e465 | ||
|
|
7d6208e0af | ||
|
|
2a105df9f2 | ||
|
|
9c731f1883 | ||
|
|
5a4e9125de | ||
|
|
9db1367c2d | ||
|
|
73c5533e66 | ||
|
|
3b1f747f96 | ||
|
|
9e9827d236 | ||
|
|
a76d508424 | ||
|
|
f881784e9b | ||
|
|
5af625903f | ||
|
|
dc94f305cc | ||
|
|
8060a49c6c | ||
|
|
2fd31f6ea6 | ||
|
|
9cf7bba8f0 | ||
|
|
2e257d1cf7 | ||
|
|
56831d7799 | ||
|
|
6d65ae5ba6 | ||
|
|
c919b4a573 | ||
|
|
fe6f392c2d | ||
|
|
3b34a537ee | ||
|
|
ad79ce9c4b | ||
|
|
721f6388c3 | ||
|
|
298ac11018 | ||
|
|
bb6e207336 | ||
|
|
f433b7c7cf | ||
|
|
a94278abd1 | ||
|
|
a7cd5a2553 | ||
|
|
0dc5836d5e | ||
|
|
8751d7ecf8 | ||
|
|
c21226aa7c | ||
|
|
3e358458f4 | ||
|
|
766b3aecf7 | ||
|
|
8ab96ab80d | ||
|
|
1f2e00ef8d | ||
|
|
b49453cf0d | ||
|
|
faffcb889c | ||
|
|
3c0ec59432 | ||
|
|
d4a2843500 | ||
|
|
e7ad49bbbe | ||
|
|
ad9a414fae | ||
|
|
c18c2a8e68 | ||
|
|
1d54868c12 | ||
|
|
f7e73e2da0 | ||
|
|
867728b5ab |
38
.gitignore
vendored
38
.gitignore
vendored
@@ -1,16 +1,26 @@
|
||||
coverage/
|
||||
.DS_Store
|
||||
*.seed
|
||||
# OS X
|
||||
.DS_Store*
|
||||
Icon?
|
||||
._*
|
||||
|
||||
# Windows
|
||||
Thumbs.db
|
||||
ehthumbs.db
|
||||
Desktop.ini
|
||||
|
||||
# Linux
|
||||
.directory
|
||||
*~
|
||||
|
||||
|
||||
# npm
|
||||
node_modules
|
||||
*.log
|
||||
*.csv
|
||||
*.dat
|
||||
*.out
|
||||
*.pid
|
||||
*.swp
|
||||
*.swo
|
||||
*.gz
|
||||
|
||||
|
||||
# Coveralls
|
||||
coverage
|
||||
|
||||
# Benchmarking
|
||||
benchmarks/graphs
|
||||
testing
|
||||
node_modules/
|
||||
testing
|
||||
test.js
|
||||
.idea
|
||||
|
||||
10
.npmignore
10
.npmignore
@@ -1,10 +0,0 @@
|
||||
.git*
|
||||
benchmarks/
|
||||
coverage/
|
||||
docs/
|
||||
examples/
|
||||
support/
|
||||
test/
|
||||
testing.js
|
||||
.DS_Store
|
||||
.travis.yml
|
||||
545
History.md
545
History.md
@@ -1,3 +1,548 @@
|
||||
3.18.4 / 2014-11-23
|
||||
===================
|
||||
|
||||
* deps: connect@2.27.4
|
||||
- deps: body-parser@~1.9.3
|
||||
- deps: compression@~1.2.1
|
||||
- deps: errorhandler@~1.2.3
|
||||
- deps: express-session@~1.9.2
|
||||
- deps: qs@2.3.3
|
||||
- deps: serve-favicon@~2.1.7
|
||||
- deps: serve-static@~1.5.1
|
||||
- deps: type-is@~1.5.3
|
||||
* deps: etag@~1.5.1
|
||||
* deps: proxy-addr@~1.0.4
|
||||
- deps: ipaddr.js@0.1.5
|
||||
|
||||
3.18.3 / 2014-11-09
|
||||
===================
|
||||
|
||||
* deps: connect@2.27.3
|
||||
- Correctly invoke async callback asynchronously
|
||||
- deps: csurf@~1.6.3
|
||||
|
||||
3.18.2 / 2014-10-28
|
||||
===================
|
||||
|
||||
* deps: connect@2.27.2
|
||||
- Fix handling of URLs containing `://` in the path
|
||||
- deps: body-parser@~1.9.2
|
||||
- deps: qs@2.3.2
|
||||
|
||||
3.18.1 / 2014-10-22
|
||||
===================
|
||||
|
||||
* Fix internal `utils.merge` deprecation warnings
|
||||
* deps: connect@2.27.1
|
||||
- deps: body-parser@~1.9.1
|
||||
- deps: express-session@~1.9.1
|
||||
- deps: finalhandler@0.3.2
|
||||
- deps: morgan@~1.4.1
|
||||
- deps: qs@2.3.0
|
||||
- deps: serve-static@~1.7.1
|
||||
* deps: send@0.10.1
|
||||
- deps: on-finished@~2.1.1
|
||||
|
||||
3.18.0 / 2014-10-17
|
||||
===================
|
||||
|
||||
* Use `content-disposition` module for `res.attachment`/`res.download`
|
||||
- Sends standards-compliant `Content-Disposition` header
|
||||
- Full Unicode support
|
||||
* Use `etag` module to generate `ETag` headers
|
||||
* deps: connect@2.27.0
|
||||
- Use `http-errors` module for creating errors
|
||||
- Use `utils-merge` module for merging objects
|
||||
- deps: body-parser@~1.9.0
|
||||
- deps: compression@~1.2.0
|
||||
- deps: connect-timeout@~1.4.0
|
||||
- deps: debug@~2.1.0
|
||||
- deps: depd@~1.0.0
|
||||
- deps: express-session@~1.9.0
|
||||
- deps: finalhandler@0.3.1
|
||||
- deps: method-override@~2.3.0
|
||||
- deps: morgan@~1.4.0
|
||||
- deps: response-time@~2.2.0
|
||||
- deps: serve-favicon@~2.1.6
|
||||
- deps: serve-index@~1.5.0
|
||||
- deps: serve-static@~1.7.0
|
||||
* deps: debug@~2.1.0
|
||||
- Implement `DEBUG_FD` env variable support
|
||||
* deps: depd@~1.0.0
|
||||
* deps: send@0.10.0
|
||||
- deps: debug@~2.1.0
|
||||
- deps: depd@~1.0.0
|
||||
- deps: etag@~1.5.0
|
||||
|
||||
3.17.8 / 2014-10-15
|
||||
===================
|
||||
|
||||
* deps: connect@2.26.6
|
||||
- deps: compression@~1.1.2
|
||||
- deps: csurf@~1.6.2
|
||||
- deps: errorhandler@~1.2.2
|
||||
|
||||
3.17.7 / 2014-10-08
|
||||
===================
|
||||
|
||||
* deps: connect@2.26.5
|
||||
- Fix accepting non-object arguments to `logger`
|
||||
- deps: serve-static@~1.6.4
|
||||
|
||||
3.17.6 / 2014-10-02
|
||||
===================
|
||||
|
||||
* deps: connect@2.26.4
|
||||
- deps: morgan@~1.3.2
|
||||
- deps: type-is@~1.5.2
|
||||
|
||||
3.17.5 / 2014-09-24
|
||||
===================
|
||||
|
||||
* deps: connect@2.26.3
|
||||
- deps: body-parser@~1.8.4
|
||||
- deps: serve-favicon@~2.1.5
|
||||
- deps: serve-static@~1.6.3
|
||||
* deps: proxy-addr@~1.0.3
|
||||
- Use `forwarded` npm module
|
||||
* deps: send@0.9.3
|
||||
- deps: etag@~1.4.0
|
||||
|
||||
3.17.4 / 2014-09-19
|
||||
===================
|
||||
|
||||
* deps: connect@2.26.2
|
||||
- deps: body-parser@~1.8.3
|
||||
- deps: qs@2.2.4
|
||||
|
||||
3.17.3 / 2014-09-18
|
||||
===================
|
||||
|
||||
* deps: proxy-addr@~1.0.2
|
||||
- Fix a global leak when multiple subnets are trusted
|
||||
- deps: ipaddr.js@0.1.3
|
||||
|
||||
3.17.2 / 2014-09-15
|
||||
===================
|
||||
|
||||
* Use `crc` instead of `buffer-crc32` for speed
|
||||
* deps: connect@2.26.1
|
||||
- deps: body-parser@~1.8.2
|
||||
- deps: depd@0.4.5
|
||||
- deps: express-session@~1.8.2
|
||||
- deps: morgan@~1.3.1
|
||||
- deps: serve-favicon@~2.1.3
|
||||
- deps: serve-static@~1.6.2
|
||||
* deps: depd@0.4.5
|
||||
* deps: send@0.9.2
|
||||
- deps: depd@0.4.5
|
||||
- deps: etag@~1.3.1
|
||||
- deps: range-parser@~1.0.2
|
||||
|
||||
3.17.1 / 2014-09-08
|
||||
===================
|
||||
|
||||
* Fix error in `req.subdomains` on empty host
|
||||
|
||||
3.17.0 / 2014-09-08
|
||||
===================
|
||||
|
||||
* Support IP address host in `req.subdomains`
|
||||
* deps: connect@2.26.0
|
||||
- deps: body-parser@~1.8.1
|
||||
- deps: compression@~1.1.0
|
||||
- deps: connect-timeout@~1.3.0
|
||||
- deps: cookie-parser@~1.3.3
|
||||
- deps: cookie-signature@1.0.5
|
||||
- deps: csurf@~1.6.1
|
||||
- deps: debug@~2.0.0
|
||||
- deps: errorhandler@~1.2.0
|
||||
- deps: express-session@~1.8.1
|
||||
- deps: finalhandler@0.2.0
|
||||
- deps: fresh@0.2.4
|
||||
- deps: media-typer@0.3.0
|
||||
- deps: method-override@~2.2.0
|
||||
- deps: morgan@~1.3.0
|
||||
- deps: qs@2.2.3
|
||||
- deps: serve-favicon@~2.1.3
|
||||
- deps: serve-index@~1.2.1
|
||||
- deps: serve-static@~1.6.1
|
||||
- deps: type-is@~1.5.1
|
||||
- deps: vhost@~3.0.0
|
||||
* deps: cookie-signature@1.0.5
|
||||
* deps: debug@~2.0.0
|
||||
* deps: fresh@0.2.4
|
||||
* deps: media-typer@0.3.0
|
||||
- Throw error when parameter format invalid on parse
|
||||
* deps: range-parser@~1.0.2
|
||||
* deps: send@0.9.1
|
||||
- Add `lastModified` option
|
||||
- Use `etag` to generate `ETag` header
|
||||
- deps: debug@~2.0.0
|
||||
- deps: fresh@0.2.4
|
||||
* deps: vary@~1.0.0
|
||||
- Accept valid `Vary` header string as `field`
|
||||
|
||||
3.16.10 / 2014-09-04
|
||||
====================
|
||||
|
||||
* deps: connect@2.25.10
|
||||
- deps: serve-static@~1.5.4
|
||||
* deps: send@0.8.5
|
||||
- Fix a path traversal issue when using `root`
|
||||
- Fix malicious path detection for empty string path
|
||||
|
||||
3.16.9 / 2014-08-29
|
||||
===================
|
||||
|
||||
* deps: connect@2.25.9
|
||||
- deps: body-parser@~1.6.7
|
||||
- deps: qs@2.2.2
|
||||
|
||||
3.16.8 / 2014-08-27
|
||||
===================
|
||||
|
||||
* deps: connect@2.25.8
|
||||
- deps: body-parser@~1.6.6
|
||||
- deps: csurf@~1.4.1
|
||||
- deps: qs@2.2.0
|
||||
|
||||
3.16.7 / 2014-08-18
|
||||
===================
|
||||
|
||||
* deps: connect@2.25.7
|
||||
- deps: body-parser@~1.6.5
|
||||
- deps: express-session@~1.7.6
|
||||
- deps: morgan@~1.2.3
|
||||
- deps: serve-static@~1.5.3
|
||||
* deps: send@0.8.3
|
||||
- deps: destroy@1.0.3
|
||||
- deps: on-finished@2.1.0
|
||||
|
||||
3.16.6 / 2014-08-14
|
||||
===================
|
||||
|
||||
* deps: connect@2.25.6
|
||||
- deps: body-parser@~1.6.4
|
||||
- deps: qs@1.2.2
|
||||
- deps: serve-static@~1.5.2
|
||||
* deps: send@0.8.2
|
||||
- Work around `fd` leak in Node.js 0.10 for `fs.ReadStream`
|
||||
|
||||
3.16.5 / 2014-08-11
|
||||
===================
|
||||
|
||||
* deps: connect@2.25.5
|
||||
- Fix backwards compatibility in `logger`
|
||||
|
||||
3.16.4 / 2014-08-10
|
||||
===================
|
||||
|
||||
* Fix original URL parsing in `res.location`
|
||||
* deps: connect@2.25.4
|
||||
- Fix `query` middleware breaking with argument
|
||||
- deps: body-parser@~1.6.3
|
||||
- deps: compression@~1.0.11
|
||||
- deps: connect-timeout@~1.2.2
|
||||
- deps: express-session@~1.7.5
|
||||
- deps: method-override@~2.1.3
|
||||
- deps: on-headers@~1.0.0
|
||||
- deps: parseurl@~1.3.0
|
||||
- deps: qs@1.2.1
|
||||
- deps: response-time@~2.0.1
|
||||
- deps: serve-index@~1.1.6
|
||||
- deps: serve-static@~1.5.1
|
||||
* deps: parseurl@~1.3.0
|
||||
|
||||
3.16.3 / 2014-08-07
|
||||
===================
|
||||
|
||||
* deps: connect@2.25.3
|
||||
- deps: multiparty@3.3.2
|
||||
|
||||
3.16.2 / 2014-08-07
|
||||
===================
|
||||
|
||||
* deps: connect@2.25.2
|
||||
- deps: body-parser@~1.6.2
|
||||
- deps: qs@1.2.0
|
||||
|
||||
3.16.1 / 2014-08-06
|
||||
===================
|
||||
|
||||
* deps: connect@2.25.1
|
||||
- deps: body-parser@~1.6.1
|
||||
- deps: qs@1.1.0
|
||||
|
||||
3.16.0 / 2014-08-05
|
||||
===================
|
||||
|
||||
* deps: connect@2.25.0
|
||||
- deps: body-parser@~1.6.0
|
||||
- deps: compression@~1.0.10
|
||||
- deps: csurf@~1.4.0
|
||||
- deps: express-session@~1.7.4
|
||||
- deps: qs@1.0.2
|
||||
- deps: serve-static@~1.5.0
|
||||
* deps: send@0.8.1
|
||||
- Add `extensions` option
|
||||
|
||||
3.15.3 / 2014-08-04
|
||||
===================
|
||||
|
||||
* fix `res.sendfile` regression for serving directory index files
|
||||
* deps: connect@2.24.3
|
||||
- deps: serve-index@~1.1.5
|
||||
- deps: serve-static@~1.4.4
|
||||
* deps: send@0.7.4
|
||||
- Fix incorrect 403 on Windows and Node.js 0.11
|
||||
- Fix serving index files without root dir
|
||||
|
||||
3.15.2 / 2014-07-27
|
||||
===================
|
||||
|
||||
* deps: connect@2.24.2
|
||||
- deps: body-parser@~1.5.2
|
||||
- deps: depd@0.4.4
|
||||
- deps: express-session@~1.7.2
|
||||
- deps: morgan@~1.2.2
|
||||
- deps: serve-static@~1.4.2
|
||||
* deps: depd@0.4.4
|
||||
- Work-around v8 generating empty stack traces
|
||||
* deps: send@0.7.2
|
||||
- deps: depd@0.4.4
|
||||
|
||||
3.15.1 / 2014-07-26
|
||||
===================
|
||||
|
||||
* deps: connect@2.24.1
|
||||
- deps: body-parser@~1.5.1
|
||||
- deps: depd@0.4.3
|
||||
- deps: express-session@~1.7.1
|
||||
- deps: morgan@~1.2.1
|
||||
- deps: serve-index@~1.1.4
|
||||
- deps: serve-static@~1.4.1
|
||||
* deps: depd@0.4.3
|
||||
- Fix exception when global `Error.stackTraceLimit` is too low
|
||||
* deps: send@0.7.1
|
||||
- deps: depd@0.4.3
|
||||
|
||||
3.15.0 / 2014-07-22
|
||||
===================
|
||||
|
||||
* Fix `req.protocol` for proxy-direct connections
|
||||
* Pass options from `res.sendfile` to `send`
|
||||
* deps: connect@2.24.0
|
||||
- deps: body-parser@~1.5.0
|
||||
- deps: compression@~1.0.9
|
||||
- deps: connect-timeout@~1.2.1
|
||||
- deps: debug@1.0.4
|
||||
- deps: depd@0.4.2
|
||||
- deps: express-session@~1.7.0
|
||||
- deps: finalhandler@0.1.0
|
||||
- deps: method-override@~2.1.2
|
||||
- deps: morgan@~1.2.0
|
||||
- deps: multiparty@3.3.1
|
||||
- deps: parseurl@~1.2.0
|
||||
- deps: serve-static@~1.4.0
|
||||
* deps: debug@1.0.4
|
||||
* deps: depd@0.4.2
|
||||
- Add `TRACE_DEPRECATION` environment variable
|
||||
- Remove non-standard grey color from color output
|
||||
- Support `--no-deprecation` argument
|
||||
- Support `--trace-deprecation` argument
|
||||
* deps: parseurl@~1.2.0
|
||||
- Cache URLs based on original value
|
||||
- Remove no-longer-needed URL mis-parse work-around
|
||||
- Simplify the "fast-path" `RegExp`
|
||||
* deps: send@0.7.0
|
||||
- Add `dotfiles` option
|
||||
- Cap `maxAge` value to 1 year
|
||||
- deps: debug@1.0.4
|
||||
- deps: depd@0.4.2
|
||||
|
||||
3.14.0 / 2014-07-11
|
||||
===================
|
||||
|
||||
* add explicit "Rosetta Flash JSONP abuse" protection
|
||||
- previous versions are not vulnerable; this is just explicit protection
|
||||
* deprecate `res.redirect(url, status)` -- use `res.redirect(status, url)` instead
|
||||
* fix `res.send(status, num)` to send `num` as json (not error)
|
||||
* remove unnecessary escaping when `res.jsonp` returns JSON response
|
||||
* deps: basic-auth@1.0.0
|
||||
- support empty password
|
||||
- support empty username
|
||||
* deps: connect@2.23.0
|
||||
- deps: debug@1.0.3
|
||||
- deps: express-session@~1.6.4
|
||||
- deps: method-override@~2.1.0
|
||||
- deps: parseurl@~1.1.3
|
||||
- deps: serve-static@~1.3.1
|
||||
* deps: debug@1.0.3
|
||||
- Add support for multiple wildcards in namespaces
|
||||
* deps: methods@1.1.0
|
||||
- add `CONNECT`
|
||||
* deps: parseurl@~1.1.3
|
||||
- faster parsing of href-only URLs
|
||||
|
||||
3.13.0 / 2014-07-03
|
||||
===================
|
||||
|
||||
* add deprecation message to `app.configure`
|
||||
* add deprecation message to `req.auth`
|
||||
* use `basic-auth` to parse `Authorization` header
|
||||
* deps: connect@2.22.0
|
||||
- deps: csurf@~1.3.0
|
||||
- deps: express-session@~1.6.1
|
||||
- deps: multiparty@3.3.0
|
||||
- deps: serve-static@~1.3.0
|
||||
* deps: send@0.5.0
|
||||
- Accept string for `maxage` (converted by `ms`)
|
||||
- Include link in default redirect response
|
||||
|
||||
3.12.1 / 2014-06-26
|
||||
===================
|
||||
|
||||
* deps: connect@2.21.1
|
||||
- deps: cookie-parser@1.3.2
|
||||
- deps: cookie-signature@1.0.4
|
||||
- deps: express-session@~1.5.2
|
||||
- deps: type-is@~1.3.2
|
||||
* deps: cookie-signature@1.0.4
|
||||
- fix for timing attacks
|
||||
|
||||
3.12.0 / 2014-06-21
|
||||
===================
|
||||
|
||||
* use `media-typer` to alter content-type charset
|
||||
* deps: connect@2.21.0
|
||||
- deprecate `connect(middleware)` -- use `app.use(middleware)` instead
|
||||
- deprecate `connect.createServer()` -- use `connect()` instead
|
||||
- fix `res.setHeader()` patch to work with with get -> append -> set pattern
|
||||
- deps: compression@~1.0.8
|
||||
- deps: errorhandler@~1.1.1
|
||||
- deps: express-session@~1.5.0
|
||||
- deps: serve-index@~1.1.3
|
||||
|
||||
3.11.0 / 2014-06-19
|
||||
===================
|
||||
|
||||
* deprecate things with `depd` module
|
||||
* deps: buffer-crc32@0.2.3
|
||||
* deps: connect@2.20.2
|
||||
- deprecate `verify` option to `json` -- use `body-parser` npm module instead
|
||||
- deprecate `verify` option to `urlencoded` -- use `body-parser` npm module instead
|
||||
- deprecate things with `depd` module
|
||||
- use `finalhandler` for final response handling
|
||||
- use `media-typer` to parse `content-type` for charset
|
||||
- deps: body-parser@1.4.3
|
||||
- deps: connect-timeout@1.1.1
|
||||
- deps: cookie-parser@1.3.1
|
||||
- deps: csurf@1.2.2
|
||||
- deps: errorhandler@1.1.0
|
||||
- deps: express-session@1.4.0
|
||||
- deps: multiparty@3.2.9
|
||||
- deps: serve-index@1.1.2
|
||||
- deps: type-is@1.3.1
|
||||
- deps: vhost@2.0.0
|
||||
|
||||
3.10.5 / 2014-06-11
|
||||
===================
|
||||
|
||||
* deps: connect@2.19.6
|
||||
- deps: body-parser@1.3.1
|
||||
- deps: compression@1.0.7
|
||||
- deps: debug@1.0.2
|
||||
- deps: serve-index@1.1.1
|
||||
- deps: serve-static@1.2.3
|
||||
* deps: debug@1.0.2
|
||||
* deps: send@0.4.3
|
||||
- Do not throw un-catchable error on file open race condition
|
||||
- Use `escape-html` for HTML escaping
|
||||
- deps: debug@1.0.2
|
||||
- deps: finished@1.2.2
|
||||
- deps: fresh@0.2.2
|
||||
|
||||
3.10.4 / 2014-06-09
|
||||
===================
|
||||
|
||||
* deps: connect@2.19.5
|
||||
- fix "event emitter leak" warnings
|
||||
- deps: csurf@1.2.1
|
||||
- deps: debug@1.0.1
|
||||
- deps: serve-static@1.2.2
|
||||
- deps: type-is@1.2.1
|
||||
* deps: debug@1.0.1
|
||||
* deps: send@0.4.2
|
||||
- fix "event emitter leak" warnings
|
||||
- deps: finished@1.2.1
|
||||
- deps: debug@1.0.1
|
||||
|
||||
3.10.3 / 2014-06-05
|
||||
===================
|
||||
|
||||
* use `vary` module for `res.vary`
|
||||
* deps: connect@2.19.4
|
||||
- deps: errorhandler@1.0.2
|
||||
- deps: method-override@2.0.2
|
||||
- deps: serve-favicon@2.0.1
|
||||
* deps: debug@1.0.0
|
||||
|
||||
3.10.2 / 2014-06-03
|
||||
===================
|
||||
|
||||
* deps: connect@2.19.3
|
||||
- deps: compression@1.0.6
|
||||
|
||||
3.10.1 / 2014-06-03
|
||||
===================
|
||||
|
||||
* deps: connect@2.19.2
|
||||
- deps: compression@1.0.4
|
||||
* deps: proxy-addr@1.0.1
|
||||
|
||||
3.10.0 / 2014-06-02
|
||||
===================
|
||||
|
||||
* deps: connect@2.19.1
|
||||
- deprecate `methodOverride()` -- use `method-override` npm module instead
|
||||
- deps: body-parser@1.3.0
|
||||
- deps: method-override@2.0.1
|
||||
- deps: multiparty@3.2.8
|
||||
- deps: response-time@2.0.0
|
||||
- deps: serve-static@1.2.1
|
||||
* deps: methods@1.0.1
|
||||
* deps: send@0.4.1
|
||||
- Send `max-age` in `Cache-Control` in correct format
|
||||
|
||||
3.9.0 / 2014-05-30
|
||||
==================
|
||||
|
||||
* custom etag control with `app.set('etag', val)`
|
||||
- `app.set('etag', function(body, encoding){ return '"etag"' })` custom etag generation
|
||||
- `app.set('etag', 'weak')` weak tag
|
||||
- `app.set('etag', 'strong')` strong etag
|
||||
- `app.set('etag', false)` turn off
|
||||
- `app.set('etag', true)` standard etag
|
||||
* Include ETag in HEAD requests
|
||||
* mark `res.send` ETag as weak and reduce collisions
|
||||
* update connect to 2.18.0
|
||||
- deps: compression@1.0.3
|
||||
- deps: serve-index@1.1.0
|
||||
- deps: serve-static@1.2.0
|
||||
* update send to 0.4.0
|
||||
- Calculate ETag with md5 for reduced collisions
|
||||
- Ignore stream errors after request ends
|
||||
- deps: debug@0.8.1
|
||||
|
||||
3.8.1 / 2014-05-27
|
||||
==================
|
||||
|
||||
* update connect to 2.17.3
|
||||
- deps: body-parser@1.2.2
|
||||
- deps: express-session@1.2.1
|
||||
- deps: method-override@1.0.2
|
||||
|
||||
3.8.0 / 2014-05-21
|
||||
==================
|
||||
|
||||
|
||||
13
Readme.md
13
Readme.md
@@ -2,7 +2,10 @@
|
||||
|
||||
Fast, unopinionated, minimalist web framework for [node](http://nodejs.org).
|
||||
|
||||
[](http://badge.fury.io/js/express) [](https://travis-ci.org/visionmedia/express) [](https://coveralls.io/r/visionmedia/express) [](https://www.gittip.com/visionmedia/)
|
||||
[](https://www.npmjs.org/package/express)
|
||||
[](https://travis-ci.org/strongloop/express)
|
||||
[](https://coveralls.io/r/strongloop/express)
|
||||
[](https://www.gittip.com/dougwilson/)
|
||||
|
||||
```js
|
||||
var express = require('express');
|
||||
@@ -62,11 +65,11 @@ app.listen(3000);
|
||||
|
||||
## More Information
|
||||
|
||||
* [Website and Documentation](http://expressjs.com/) stored at [visionmedia/expressjs.com](https://github.com/visionmedia/expressjs.com)
|
||||
* [Website and Documentation](http://expressjs.com/) stored at [strongloop/expressjs.com](https://github.com/strongloop/expressjs.com)
|
||||
* Join #express on freenode
|
||||
* [Google Group](http://groups.google.com/group/express-js) for discussion
|
||||
* Follow [tjholowaychuk](http://twitter.com/tjholowaychuk) on twitter for updates
|
||||
* Visit the [Wiki](http://github.com/visionmedia/express/wiki)
|
||||
* Visit the [Wiki](http://github.com/strongloop/express/wiki)
|
||||
* [Русскоязычная документация](http://jsman.ru/express/)
|
||||
* Run express examples [online](https://runnable.com/express)
|
||||
|
||||
@@ -74,7 +77,7 @@ app.listen(3000);
|
||||
|
||||
Clone the Express repo, then install the dev dependencies to install all the example / test suite dependencies:
|
||||
|
||||
$ git clone git://github.com/visionmedia/express.git --depth 1
|
||||
$ git clone git://github.com/strongloop/express.git --depth 1
|
||||
$ cd express
|
||||
$ npm install
|
||||
|
||||
@@ -100,7 +103,7 @@ $ npm test
|
||||
|
||||
## Contributors
|
||||
|
||||
https://github.com/visionmedia/express/graphs/contributors
|
||||
https://github.com/strongloop/express/graphs/contributors
|
||||
|
||||
## License
|
||||
|
||||
|
||||
@@ -335,7 +335,7 @@ function createApplicationAt(path) {
|
||||
|
||||
// Session support
|
||||
app = app.replace('{sess}', program.sessions
|
||||
? eol + 'app.use(express.cookieParser(\'your secret here\'));' + eol + 'app.use(express.session());'
|
||||
? eol + 'app.use(express.session({ secret: \'your secret here\' }));'
|
||||
: '');
|
||||
|
||||
// Template support
|
||||
|
||||
@@ -14,9 +14,8 @@ app.set('views', __dirname + '/views');
|
||||
|
||||
// middleware
|
||||
|
||||
app.use(express.bodyParser());
|
||||
app.use(express.cookieParser('shhhh, very secret'));
|
||||
app.use(express.session());
|
||||
app.use(express.urlencoded({ extended: false }));
|
||||
app.use(express.session({ secret: 'shhhh, very secret' }));
|
||||
|
||||
// Session-persisted message middleware
|
||||
|
||||
@@ -118,6 +117,7 @@ app.post('/login', function(req, res){
|
||||
});
|
||||
});
|
||||
|
||||
/* istanbul ignore next */
|
||||
if (!module.parent) {
|
||||
app.listen(3000);
|
||||
console.log('Express started on port 3000');
|
||||
|
||||
@@ -20,5 +20,8 @@ app.get('/', function(req, res){
|
||||
res.render('pets', { pets: pets });
|
||||
});
|
||||
|
||||
app.listen(3000);
|
||||
console.log('Express listening on port 3000');
|
||||
/* istanbul ignore next */
|
||||
if (!module.parent) {
|
||||
app.listen(3000);
|
||||
console.log('Express started on port 3000');
|
||||
}
|
||||
|
||||
@@ -37,7 +37,8 @@ function format(path) {
|
||||
|
||||
app.get('/users', format('./users'));
|
||||
|
||||
/* istanbul ignore next */
|
||||
if (!module.parent) {
|
||||
app.listen(3000);
|
||||
console.log('listening on port 3000');
|
||||
console.log('Express started on port 3000');
|
||||
}
|
||||
|
||||
@@ -26,7 +26,8 @@ function count(req, res) {
|
||||
res.send('viewed ' + n + ' times\n');
|
||||
}
|
||||
|
||||
/* istanbul ignore next */
|
||||
if (!module.parent) {
|
||||
app.listen(3000);
|
||||
console.log('Express server listening on port 3000');
|
||||
}
|
||||
console.log('Express started on port 3000');
|
||||
}
|
||||
|
||||
@@ -15,8 +15,7 @@ var express = require('../../')
|
||||
app.use(express.favicon());
|
||||
|
||||
// custom log format
|
||||
if ('test' != process.env.NODE_ENV)
|
||||
app.use(express.logger(':method :url'));
|
||||
if ('test' != process.env.NODE_ENV) app.use(express.logger(':method :url'));
|
||||
|
||||
// parses request cookies, populating
|
||||
// req.cookies and req.signedCookies
|
||||
@@ -48,7 +47,8 @@ app.post('/', function(req, res){
|
||||
res.redirect('back');
|
||||
});
|
||||
|
||||
if (!module.parent){
|
||||
/* istanbul ignore next */
|
||||
if (!module.parent) {
|
||||
app.listen(3000);
|
||||
console.log('Express started on port 3000');
|
||||
}
|
||||
}
|
||||
|
||||
@@ -38,7 +38,8 @@ app.use(function(err, req, res, next){
|
||||
}
|
||||
});
|
||||
|
||||
/* istanbul ignore next */
|
||||
if (!module.parent) {
|
||||
app.listen(3000);
|
||||
console.log('Express started on port 3000');
|
||||
}
|
||||
}
|
||||
|
||||
@@ -44,7 +44,8 @@ app.get('/', function(req, res){
|
||||
});
|
||||
});
|
||||
|
||||
/* istanbul ignore next */
|
||||
if (!module.parent) {
|
||||
app.listen(3000);
|
||||
console.log('Express app started on port 3000');
|
||||
console.log('Express started on port 3000');
|
||||
}
|
||||
|
||||
@@ -17,9 +17,7 @@ app.enable('verbose errors');
|
||||
|
||||
// disable them in production
|
||||
// use $ NODE_ENV=production node examples/error-pages
|
||||
if ('production' == app.settings.env) {
|
||||
app.disable('verbose errors');
|
||||
}
|
||||
if ('production' == app.settings.env) app.disable('verbose errors');
|
||||
|
||||
app.use(express.favicon());
|
||||
|
||||
@@ -106,7 +104,8 @@ app.get('/500', function(req, res, next){
|
||||
next(new Error('keyboard cat!'));
|
||||
});
|
||||
|
||||
/* istanbul ignore next */
|
||||
if (!module.parent) {
|
||||
app.listen(3000);
|
||||
silent || console.log('Express started on port 3000');
|
||||
}
|
||||
console.log('Express started on port 3000');
|
||||
}
|
||||
|
||||
@@ -42,7 +42,8 @@ app.get('/next', function(req, res, next){
|
||||
});
|
||||
});
|
||||
|
||||
/* istanbul ignore next */
|
||||
if (!module.parent) {
|
||||
app.listen(3000);
|
||||
console.log('Express started on port 3000');
|
||||
}
|
||||
}
|
||||
|
||||
@@ -56,5 +56,8 @@ app.get('/user', function(req, res){
|
||||
res.render('page');
|
||||
});
|
||||
|
||||
app.listen(3000);
|
||||
console.log('app listening on port 3000');
|
||||
/* istanbul ignore next */
|
||||
if (!module.parent) {
|
||||
app.listen(3000);
|
||||
console.log('Express started on port 3000');
|
||||
}
|
||||
|
||||
@@ -7,5 +7,8 @@ app.get('/', function(req, res){
|
||||
res.send('Hello World');
|
||||
});
|
||||
|
||||
app.listen(3000);
|
||||
console.log('Express started on port 3000');
|
||||
/* istanbul ignore next */
|
||||
if (!module.parent) {
|
||||
app.listen(3000);
|
||||
console.log('Express started on port 3000');
|
||||
}
|
||||
|
||||
@@ -41,5 +41,8 @@ app.get('/', function(req, res){
|
||||
res.render('users', { users: users });
|
||||
});
|
||||
|
||||
app.listen(3000);
|
||||
console.log('Express app started on port 3000');
|
||||
/* istanbul ignore next */
|
||||
if (!module.parent) {
|
||||
app.listen(3000);
|
||||
console.log('Express started on port 3000');
|
||||
}
|
||||
|
||||
@@ -39,6 +39,7 @@ app.get('/fail', function(req, res){
|
||||
res.render('missing', { title: 'Markdown Example' });
|
||||
})
|
||||
|
||||
/* istanbul ignore next */
|
||||
if (!module.parent) {
|
||||
app.listen(3000);
|
||||
console.log('Express started on port 3000');
|
||||
|
||||
@@ -30,7 +30,8 @@ app.post('/', function(req, res, next){
|
||||
, req.body.title));
|
||||
});
|
||||
|
||||
/* istanbul ignore next */
|
||||
if (!module.parent) {
|
||||
app.listen(3000);
|
||||
console.log('Express started on port 3000');
|
||||
}
|
||||
}
|
||||
|
||||
@@ -31,11 +31,10 @@ if (!module.parent) app.use(express.logger('dev'));
|
||||
app.use(express.static(__dirname + '/public'));
|
||||
|
||||
// session support
|
||||
app.use(express.cookieParser('some secret here'));
|
||||
app.use(express.session());
|
||||
app.use(express.session({ secret: 'some secret here' }));
|
||||
|
||||
// parse request bodies (req.body)
|
||||
app.use(express.bodyParser());
|
||||
app.use(express.urlencoded({ extended: true }));
|
||||
|
||||
// support _method (PUT in forms etc)
|
||||
app.use(express.methodOverride());
|
||||
@@ -86,7 +85,8 @@ app.use(function(req, res, next){
|
||||
res.status(404).render('404', { url: req.originalUrl });
|
||||
});
|
||||
|
||||
/* istanbul ignore next */
|
||||
if (!module.parent) {
|
||||
app.listen(3000);
|
||||
console.log('\n listening on port 3000\n');
|
||||
console.log('Express started on port 3000');
|
||||
}
|
||||
|
||||
@@ -50,5 +50,8 @@ app.get('/', function(req, res, next){
|
||||
});
|
||||
});
|
||||
|
||||
app.listen(3000);
|
||||
console.log('listening on port 3000');
|
||||
/* istanbul ignore next */
|
||||
if (!module.parent) {
|
||||
app.listen(3000);
|
||||
console.log('Express started on port 3000');
|
||||
}
|
||||
|
||||
@@ -19,8 +19,8 @@ var users = [
|
||||
// Convert :to and :from to integers
|
||||
|
||||
app.param(['to', 'from'], function(req, res, next, num, name){
|
||||
req.params[name] = num = parseInt(num, 10);
|
||||
if( isNaN(num) ){
|
||||
req.params[name] = parseInt(num, 10);
|
||||
if( isNaN(req.params[name]) ){
|
||||
next(new Error('failed to parseInt '+num));
|
||||
} else {
|
||||
next();
|
||||
@@ -64,7 +64,8 @@ app.get('/users/:from-:to', function(req, res, next){
|
||||
res.send('users ' + names.slice(from, to).join(', '));
|
||||
});
|
||||
|
||||
/* istanbul ignore next */
|
||||
if (!module.parent) {
|
||||
app.listen(3000);
|
||||
console.log('Express started on port 3000');
|
||||
}
|
||||
}
|
||||
|
||||
@@ -18,7 +18,10 @@ app.resource = function(path, obj) {
|
||||
obj.range(req, res, a, b, format);
|
||||
});
|
||||
this.get(path + '/:id', obj.show);
|
||||
this.delete(path + '/:id', obj.destroy);
|
||||
this.delete(path + '/:id', function(req, res){
|
||||
var id = parseInt(req.params.id, 10);
|
||||
obj.destroy(req, res, id);
|
||||
});
|
||||
};
|
||||
|
||||
// Fake records
|
||||
@@ -41,8 +44,7 @@ var User = {
|
||||
show: function(req, res){
|
||||
res.send(users[req.params.id] || { error: 'Cannot find user' });
|
||||
},
|
||||
destroy: function(req, res){
|
||||
var id = req.params.id;
|
||||
destroy: function(req, res, id){
|
||||
var destroyed = id in users;
|
||||
delete users[id];
|
||||
res.send(destroyed ? 'destroyed' : 'Cannot find user');
|
||||
@@ -85,7 +87,8 @@ app.get('/', function(req, res){
|
||||
].join('\n'));
|
||||
});
|
||||
|
||||
/* istanbul ignore next */
|
||||
if (!module.parent) {
|
||||
app.listen(3000);
|
||||
console.log('Express started on port 3000');
|
||||
}
|
||||
}
|
||||
|
||||
@@ -60,4 +60,8 @@ app.map({
|
||||
}
|
||||
});
|
||||
|
||||
app.listen(3000);
|
||||
/* istanbul ignore next */
|
||||
if (!module.parent) {
|
||||
app.listen(3000);
|
||||
console.log('Express started on port 3000');
|
||||
}
|
||||
|
||||
@@ -81,5 +81,8 @@ app.delete('/user/:id', loadUser, andRestrictTo('admin'), function(req, res){
|
||||
res.send('Deleted user ' + req.user.name);
|
||||
});
|
||||
|
||||
app.listen(3000);
|
||||
console.log('Express app started on port 3000');
|
||||
/* istanbul ignore next */
|
||||
if (!module.parent) {
|
||||
app.listen(3000);
|
||||
console.log('Express started on port 3000');
|
||||
}
|
||||
|
||||
@@ -36,5 +36,8 @@ app.put('/user/:id/edit', user.update);
|
||||
|
||||
app.get('/posts', post.list);
|
||||
|
||||
app.listen(3000);
|
||||
console.log('Express app started on port 3000');
|
||||
/* istanbul ignore next */
|
||||
if (!module.parent) {
|
||||
app.listen(3000);
|
||||
console.log('Express started on port 3000');
|
||||
}
|
||||
|
||||
@@ -57,5 +57,8 @@ app.get('/client.js', function(req, res){
|
||||
res.sendfile(__dirname + '/client.js');
|
||||
});
|
||||
|
||||
app.listen(3000);
|
||||
console.log('app listening on port 3000');
|
||||
/* istanbul ignore next */
|
||||
if (!module.parent) {
|
||||
app.listen(3000);
|
||||
console.log('Express started on port 3000');
|
||||
}
|
||||
|
||||
@@ -9,13 +9,8 @@ var app = express();
|
||||
|
||||
app.use(express.logger('dev'));
|
||||
|
||||
// Required by session() middleware
|
||||
// pass the secret for signed cookies
|
||||
// (required by session())
|
||||
app.use(express.cookieParser('keyboard cat'));
|
||||
|
||||
// Populates req.session
|
||||
app.use(express.session());
|
||||
app.use(express.session({ secret: 'keyboard cat' }));
|
||||
|
||||
app.get('/', function(req, res){
|
||||
var body = '';
|
||||
@@ -28,5 +23,8 @@ app.get('/', function(req, res){
|
||||
res.send(body + '<p>viewed <strong>' + req.session.views + '</strong> times.</p>');
|
||||
});
|
||||
|
||||
app.listen(3000);
|
||||
console.log('Express app started on port 3000');
|
||||
/* istanbul ignore next */
|
||||
if (!module.parent) {
|
||||
app.listen(3000);
|
||||
console.log('Express started on port 3000');
|
||||
}
|
||||
|
||||
@@ -10,13 +10,8 @@ var app = express();
|
||||
|
||||
app.use(express.logger('dev'));
|
||||
|
||||
// Required by session() middleware
|
||||
// pass the secret for signed cookies
|
||||
// (required by session())
|
||||
app.use(express.cookieParser('keyboard cat'));
|
||||
|
||||
// Populates req.session
|
||||
app.use(express.session({ store: new RedisStore }));
|
||||
app.use(express.session({ store: new RedisStore, secret: 'keyboard cat' }));
|
||||
|
||||
app.get('/', function(req, res){
|
||||
var body = '';
|
||||
|
||||
@@ -42,5 +42,8 @@ var app = express();
|
||||
app.use(express.vhost('*.example.com', redirect)) // Serves all subdomains via Redirect app
|
||||
app.use(express.vhost('example.com', main)); // Serves top level domain via Main server app
|
||||
|
||||
app.listen(3000);
|
||||
console.log('Express app started on port 3000');
|
||||
/* istanbul ignore next */
|
||||
if (!module.parent) {
|
||||
app.listen(3000);
|
||||
console.log('Express started on port 3000');
|
||||
}
|
||||
|
||||
@@ -35,13 +35,13 @@ function GithubView(name, options){
|
||||
GithubView.prototype.render = function(options, fn){
|
||||
var self = this;
|
||||
var opts = {
|
||||
host: 'rawgithub.com',
|
||||
port: 80,
|
||||
host: 'raw.githubusercontent.com',
|
||||
port: 443,
|
||||
path: this.path,
|
||||
method: 'GET'
|
||||
};
|
||||
|
||||
http.request(opts, function(res) {
|
||||
https.request(opts, function(res) {
|
||||
var buf = '';
|
||||
res.setEncoding('utf8');
|
||||
res.on('data', function(str){ buf += str });
|
||||
|
||||
@@ -24,7 +24,7 @@ app.engine('md', function(str, options, fn){
|
||||
})
|
||||
|
||||
// pointing to a particular github repo to load files from it
|
||||
app.set('views', 'visionmedia/express');
|
||||
app.set('views', 'strongloop/express');
|
||||
|
||||
// register a new view constructor
|
||||
app.set('view', GithubView);
|
||||
@@ -37,10 +37,11 @@ app.get('/', function(req, res){
|
||||
})
|
||||
|
||||
app.get('/Readme.md', function(req, res){
|
||||
// rendering a view from https://github.com/visionmedia/express/blob/master/Readme.md
|
||||
// rendering a view from https://github.com/strongloop/express/blob/master/Readme.md
|
||||
res.render('Readme.md');
|
||||
})
|
||||
|
||||
/* istanbul ignore next */
|
||||
if (!module.parent) {
|
||||
app.listen(3000);
|
||||
console.log('Express started on port 3000');
|
||||
|
||||
@@ -142,5 +142,8 @@ app.all('/api/*', function(req, res, next){
|
||||
|
||||
*/
|
||||
|
||||
app.listen(3000);
|
||||
console.log('Application listening on port 3000');
|
||||
/* istanbul ignore next */
|
||||
if (!module.parent) {
|
||||
app.listen(3000);
|
||||
console.log('Express started on port 3000');
|
||||
}
|
||||
|
||||
@@ -73,7 +73,7 @@ var apiKeys = ['foo', 'bar', 'baz'];
|
||||
// these two objects will serve as our faux database
|
||||
|
||||
var repos = [
|
||||
{ name: 'express', url: 'http://github.com/visionmedia/express' }
|
||||
{ name: 'express', url: 'http://github.com/strongloop/express' }
|
||||
, { name: 'stylus', url: 'http://github.com/learnboost/stylus' }
|
||||
, { name: 'cluster', url: 'http://github.com/learnboost/cluster' }
|
||||
];
|
||||
@@ -109,7 +109,8 @@ app.get('/api/user/:name/repos', function(req, res, next){
|
||||
else next();
|
||||
});
|
||||
|
||||
/* istanbul ignore next */
|
||||
if (!module.parent) {
|
||||
app.listen(3000);
|
||||
console.log('Express server listening on port 3000');
|
||||
}
|
||||
console.log('Express started on port 3000');
|
||||
}
|
||||
|
||||
@@ -8,11 +8,12 @@ var connect = require('connect')
|
||||
, middleware = require('./middleware')
|
||||
, debug = require('debug')('express:application')
|
||||
, locals = require('./utils').locals
|
||||
, compileETag = require('./utils').compileETag
|
||||
, compileTrust = require('./utils').compileTrust
|
||||
, View = require('./view')
|
||||
, utils = connect.utils
|
||||
, deprecate = require('./utils').deprecate
|
||||
, http = require('http');
|
||||
var deprecate = require('depd')('express');
|
||||
var merge = require('utils-merge');
|
||||
|
||||
/**
|
||||
* Application prototype.
|
||||
@@ -46,11 +47,13 @@ app.init = function(){
|
||||
app.defaultConfiguration = function(){
|
||||
// default settings
|
||||
this.enable('x-powered-by');
|
||||
this.enable('etag');
|
||||
this.set('env', process.env.NODE_ENV || 'development');
|
||||
this.set('etag', 'weak');
|
||||
var env = process.env.NODE_ENV || 'development';
|
||||
this.set('env', env);
|
||||
this.set('subdomain offset', 2);
|
||||
this.set('trust proxy', false);
|
||||
debug('booting in %s mode', this.get('env'));
|
||||
|
||||
debug('booting in %s mode', env);
|
||||
|
||||
// implicit middleware
|
||||
this.use(connect.query());
|
||||
@@ -85,13 +88,13 @@ app.defaultConfiguration = function(){
|
||||
this.set('views', process.cwd() + '/views');
|
||||
this.set('jsonp callback name', 'callback');
|
||||
|
||||
this.configure('development', function(){
|
||||
if (env === 'development') {
|
||||
this.set('json spaces', 2);
|
||||
});
|
||||
}
|
||||
|
||||
this.configure('production', function(){
|
||||
if (env === 'production') {
|
||||
this.enable('view cache');
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -251,18 +254,27 @@ app.param = function(name, fn){
|
||||
*/
|
||||
|
||||
app.set = function(setting, val){
|
||||
if (1 == arguments.length) {
|
||||
if (arguments.length === 1) {
|
||||
// app.get(setting)
|
||||
return this.settings[setting];
|
||||
} else {
|
||||
this.settings[setting] = val;
|
||||
|
||||
if (setting === 'trust proxy') {
|
||||
debug('compile trust proxy %j', val);
|
||||
this.set('trust proxy fn', compileTrust(val));
|
||||
}
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
// set value
|
||||
this.settings[setting] = val;
|
||||
|
||||
// trigger matched settings
|
||||
switch (setting) {
|
||||
case 'etag':
|
||||
debug('compile etag %s', val);
|
||||
this.set('etag fn', compileETag(val));
|
||||
break;
|
||||
case 'trust proxy':
|
||||
debug('compile trust proxy %s', val);
|
||||
this.set('trust proxy fn', compileTrust(val));
|
||||
break;
|
||||
}
|
||||
|
||||
return this;
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -401,6 +413,9 @@ app.configure = function(env, fn){
|
||||
return this;
|
||||
};
|
||||
|
||||
app.configure = deprecate.function(app.configure,
|
||||
'app.configure: Check app.get(\'env\') in an if statement');
|
||||
|
||||
/**
|
||||
* Delegate `.VERB(...)` calls to `router.VERB(...)`.
|
||||
*/
|
||||
@@ -438,7 +453,7 @@ app.all = function(path){
|
||||
|
||||
// del -> delete alias
|
||||
|
||||
app.del = deprecate(app.delete, 'app.del: Use app.delete instead');
|
||||
app.del = deprecate.function(app.delete, 'app.del: Use app.delete instead');
|
||||
|
||||
/**
|
||||
* Render the given view `name` name with `options`
|
||||
@@ -469,13 +484,15 @@ app.render = function(name, options, fn){
|
||||
}
|
||||
|
||||
// merge app.locals
|
||||
utils.merge(opts, this.locals);
|
||||
merge(opts, this.locals);
|
||||
|
||||
// merge options._locals
|
||||
if (options._locals) utils.merge(opts, options._locals);
|
||||
if (options._locals) {
|
||||
merge(opts, options._locals);
|
||||
}
|
||||
|
||||
// merge options
|
||||
utils.merge(opts, options);
|
||||
merge(opts, options);
|
||||
|
||||
// set .cache unless explicitly provided
|
||||
opts.cache = null == opts.cache
|
||||
|
||||
@@ -2,15 +2,15 @@
|
||||
* Module dependencies.
|
||||
*/
|
||||
|
||||
var merge = require('merge-descriptors');
|
||||
var deprecate = require('depd')('express');
|
||||
var mixin = require('merge-descriptors');
|
||||
var merge = require('utils-merge');
|
||||
var connect = require('connect')
|
||||
, proto = require('./application')
|
||||
, Route = require('./router/route')
|
||||
, Router = require('./router')
|
||||
, req = require('./request')
|
||||
, res = require('./response')
|
||||
, deprecate = require('./utils').deprecate
|
||||
, utils = connect.utils;
|
||||
, res = require('./response');
|
||||
|
||||
/**
|
||||
* Expose `createApplication()`.
|
||||
@@ -33,7 +33,7 @@ exports.mime = connect.mime;
|
||||
|
||||
function createApplication() {
|
||||
var app = connect();
|
||||
utils.merge(app, proto);
|
||||
merge(app, proto);
|
||||
app.request = { __proto__: req, app: app };
|
||||
app.response = { __proto__: res, app: app };
|
||||
app.init();
|
||||
@@ -45,13 +45,13 @@ function createApplication() {
|
||||
* for example `express.logger` etc.
|
||||
*/
|
||||
|
||||
merge(exports, connect.middleware);
|
||||
mixin(exports, connect.middleware);
|
||||
|
||||
/**
|
||||
* Deprecated createServer().
|
||||
*/
|
||||
|
||||
exports.createServer = deprecate(createApplication,
|
||||
exports.createServer = deprecate.function(createApplication,
|
||||
'createServer() is deprecated\n' +
|
||||
'express applications no longer inherit from http.Server\n' +
|
||||
'please use:\n' +
|
||||
|
||||
@@ -3,6 +3,8 @@
|
||||
* Module dependencies.
|
||||
*/
|
||||
|
||||
var auth = require('basic-auth');
|
||||
var deprecate = require('depd')('express');
|
||||
var http = require('http')
|
||||
, utils = require('./utils')
|
||||
, connect = require('connect')
|
||||
@@ -11,6 +13,7 @@ var http = require('http')
|
||||
, parse = require('parseurl')
|
||||
, proxyaddr = require('proxy-addr')
|
||||
, mime = connect.mime;
|
||||
var isIP = require('net').isIP;
|
||||
|
||||
/**
|
||||
* Request prototype.
|
||||
@@ -339,7 +342,9 @@ req.is = function(type){
|
||||
* Return the protocol string "http" or "https"
|
||||
* when requested with TLS. When the "trust proxy"
|
||||
* setting trusts the socket address, the
|
||||
* "X-Forwarded-Proto" header field will be trusted.
|
||||
* "X-Forwarded-Proto" header field will be trusted
|
||||
* and used if present.
|
||||
*
|
||||
* If you're running behind a reverse proxy that
|
||||
* supplies https for you this may be enabled.
|
||||
*
|
||||
@@ -348,17 +353,18 @@ req.is = function(type){
|
||||
*/
|
||||
|
||||
req.__defineGetter__('protocol', function(){
|
||||
var proto = this.connection.encrypted
|
||||
? 'https'
|
||||
: 'http';
|
||||
var trust = this.app.get('trust proxy fn');
|
||||
|
||||
if (!trust(this.connection.remoteAddress)) {
|
||||
return this.connection.encrypted
|
||||
? 'https'
|
||||
: 'http';
|
||||
return proto;
|
||||
}
|
||||
|
||||
// Note: X-Forwarded-Proto is normally only ever a
|
||||
// single value, but this is to be safe.
|
||||
var proto = this.get('X-Forwarded-Proto') || 'http';
|
||||
proto = this.get('X-Forwarded-Proto') || proto;
|
||||
return proto.split(/\s*,\s*/)[0];
|
||||
});
|
||||
|
||||
@@ -422,20 +428,13 @@ req.__defineGetter__('ips', function(){
|
||||
*/
|
||||
|
||||
req.__defineGetter__('auth', function(){
|
||||
// missing
|
||||
var auth = this.get('Authorization');
|
||||
if (!auth) return;
|
||||
|
||||
// malformed
|
||||
var parts = auth.split(' ');
|
||||
if ('basic' != parts[0].toLowerCase()) return;
|
||||
if (!parts[1]) return;
|
||||
auth = parts[1];
|
||||
deprecate('req.auth: Use basic-auth npm module instead');
|
||||
|
||||
// credentials
|
||||
auth = new Buffer(auth, 'base64').toString().match(/^([^:]*):(.*)$/);
|
||||
if (!auth) return;
|
||||
return { username: auth[1], password: auth[2] };
|
||||
var creds = auth(this);
|
||||
if (!creds) return;
|
||||
|
||||
return { username: creds.name, password: creds.pass };
|
||||
});
|
||||
|
||||
/**
|
||||
@@ -454,11 +453,16 @@ req.__defineGetter__('auth', function(){
|
||||
*/
|
||||
|
||||
req.__defineGetter__('subdomains', function(){
|
||||
var host = this.host;
|
||||
|
||||
if (!host) return [];
|
||||
|
||||
var offset = this.app.get('subdomain offset');
|
||||
return (this.host || '')
|
||||
.split('.')
|
||||
.reverse()
|
||||
.slice(offset);
|
||||
var subdomains = !isIP(host)
|
||||
? host.split('.').reverse()
|
||||
: [host];
|
||||
|
||||
return subdomains.slice(offset);
|
||||
});
|
||||
|
||||
/**
|
||||
|
||||
181
lib/response.js
181
lib/response.js
@@ -2,16 +2,19 @@
|
||||
* Module dependencies.
|
||||
*/
|
||||
|
||||
var contentDisposition = require('content-disposition');
|
||||
var deprecate = require('depd')('express');
|
||||
var escapeHtml = require('escape-html');
|
||||
var merge = require('utils-merge');
|
||||
var parseUrl = require('parseurl');
|
||||
var vary = require('vary');
|
||||
var http = require('http')
|
||||
, path = require('path')
|
||||
, connect = require('connect')
|
||||
, utils = connect.utils
|
||||
, sign = require('cookie-signature').sign
|
||||
, normalizeType = require('./utils').normalizeType
|
||||
, normalizeTypes = require('./utils').normalizeTypes
|
||||
, setCharset = require('./utils').setCharset
|
||||
, deprecate = require('./utils').deprecate
|
||||
, etag = require('./utils').etag
|
||||
, statusCodes = http.STATUS_CODES
|
||||
, cookie = require('cookie')
|
||||
, send = require('send')
|
||||
@@ -102,13 +105,15 @@ res.send = function(body){
|
||||
}
|
||||
}
|
||||
|
||||
// disambiguate res.send(status) and res.send(status, num)
|
||||
if (typeof body === 'number' && arguments.length === 1) {
|
||||
// res.send(status) will set status message as text string
|
||||
this.get('Content-Type') || this.type('txt');
|
||||
this.statusCode = body;
|
||||
body = http.STATUS_CODES[body];
|
||||
}
|
||||
|
||||
switch (typeof body) {
|
||||
// response status
|
||||
case 'number':
|
||||
this.get('Content-Type') || this.type('txt');
|
||||
this.statusCode = body;
|
||||
body = http.STATUS_CODES[body];
|
||||
break;
|
||||
// string defaulting to html
|
||||
case 'string':
|
||||
if (!this.get('Content-Type')) {
|
||||
@@ -117,6 +122,7 @@ res.send = function(body){
|
||||
}
|
||||
break;
|
||||
case 'boolean':
|
||||
case 'number':
|
||||
case 'object':
|
||||
if (null == body) {
|
||||
body = '';
|
||||
@@ -128,21 +134,6 @@ res.send = function(body){
|
||||
break;
|
||||
}
|
||||
|
||||
// populate Content-Length
|
||||
if (undefined !== body && !this.get('Content-Length')) {
|
||||
this.set('Content-Length', len = Buffer.isBuffer(body)
|
||||
? body.length
|
||||
: Buffer.byteLength(body));
|
||||
}
|
||||
|
||||
// ETag support
|
||||
// TODO: W/ support
|
||||
if (app.settings.etag && len && 'GET' == req.method) {
|
||||
if (!this.get('ETag')) {
|
||||
this.set('ETag', etag(body));
|
||||
}
|
||||
}
|
||||
|
||||
// write strings in utf-8
|
||||
if ('string' === typeof body) {
|
||||
encoding = 'utf8';
|
||||
@@ -154,6 +145,23 @@ res.send = function(body){
|
||||
}
|
||||
}
|
||||
|
||||
// populate Content-Length
|
||||
if (undefined !== body && !this.get('Content-Length')) {
|
||||
len = Buffer.isBuffer(body)
|
||||
? body.length
|
||||
: Buffer.byteLength(body, encoding);
|
||||
this.set('Content-Length', len);
|
||||
}
|
||||
|
||||
// ETag support
|
||||
var etag = len !== undefined && app.get('etag fn');
|
||||
if (etag && ('GET' === req.method || 'HEAD' === req.method)) {
|
||||
if (!this.get('ETag')) {
|
||||
etag = etag(body, encoding);
|
||||
etag && this.set('ETag', etag);
|
||||
}
|
||||
}
|
||||
|
||||
// freshness
|
||||
if (req.fresh) this.statusCode = 304;
|
||||
|
||||
@@ -193,9 +201,11 @@ res.json = function(obj){
|
||||
// res.json(body, status) backwards compat
|
||||
if ('number' == typeof arguments[1]) {
|
||||
this.statusCode = arguments[1];
|
||||
return 'number' === typeof obj
|
||||
? jsonNumDeprecated.call(this, obj)
|
||||
: jsonDeprecated.call(this, obj);
|
||||
if (typeof obj === 'number') {
|
||||
deprecate('res.json(obj, status): Use res.json(status, obj) instead');
|
||||
} else {
|
||||
deprecate('res.json(num, status): Use res.status(status).json(num) instead');
|
||||
}
|
||||
} else {
|
||||
this.statusCode = obj;
|
||||
obj = arguments[1];
|
||||
@@ -215,12 +225,6 @@ res.json = function(obj){
|
||||
return this.send(body);
|
||||
};
|
||||
|
||||
var jsonDeprecated = deprecate(res.json,
|
||||
'res.json(obj, status): Use res.json(status, obj) instead');
|
||||
|
||||
var jsonNumDeprecated = deprecate(res.json,
|
||||
'res.json(num, status): Use res.status(status).json(num) instead');
|
||||
|
||||
/**
|
||||
* Send JSON response with JSONP callback support.
|
||||
*
|
||||
@@ -243,9 +247,11 @@ res.jsonp = function(obj){
|
||||
// res.json(body, status) backwards compat
|
||||
if ('number' == typeof arguments[1]) {
|
||||
this.statusCode = arguments[1];
|
||||
return 'number' === typeof obj
|
||||
? jsonpNumDeprecated.call(this, obj)
|
||||
: jsonpDeprecated.call(this, obj);
|
||||
if (typeof obj === 'number') {
|
||||
deprecate('res.jsonp(obj, status): Use res.jsonp(status, obj) instead');
|
||||
} else {
|
||||
deprecate('res.jsonp(num, status): Use res.status(status).jsonp(num) instead');
|
||||
}
|
||||
} else {
|
||||
this.statusCode = obj;
|
||||
obj = arguments[1];
|
||||
@@ -256,14 +262,15 @@ res.jsonp = function(obj){
|
||||
var app = this.app;
|
||||
var replacer = app.get('json replacer');
|
||||
var spaces = app.get('json spaces');
|
||||
var body = JSON.stringify(obj, replacer, spaces)
|
||||
.replace(/\u2028/g, '\\u2028')
|
||||
.replace(/\u2029/g, '\\u2029');
|
||||
var body = JSON.stringify(obj, replacer, spaces);
|
||||
var callback = this.req.query[app.get('jsonp callback name')];
|
||||
|
||||
// content-type
|
||||
this.charset = this.charset || 'utf-8';
|
||||
this.get('Content-Type') || this.set('Content-Type', 'application/json');
|
||||
if (!this.get('Content-Type')) {
|
||||
this.charset = 'utf-8';
|
||||
this.set('X-Content-Type-Options', 'nosniff');
|
||||
this.set('Content-Type', 'application/json');
|
||||
}
|
||||
|
||||
// fixup callback
|
||||
if (Array.isArray(callback)) {
|
||||
@@ -271,21 +278,27 @@ res.jsonp = function(obj){
|
||||
}
|
||||
|
||||
// jsonp
|
||||
if (callback && 'string' === typeof callback) {
|
||||
if (typeof callback === 'string' && callback.length !== 0) {
|
||||
this.charset = 'utf-8';
|
||||
this.set('X-Content-Type-Options', 'nosniff');
|
||||
this.set('Content-Type', 'text/javascript');
|
||||
var cb = callback.replace(/[^\[\]\w$.]/g, '');
|
||||
body = 'typeof ' + cb + ' === \'function\' && ' + cb + '(' + body + ');';
|
||||
|
||||
// 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');
|
||||
|
||||
// the /**/ is a specific security mitigation for "Rosetta Flash JSONP abuse"
|
||||
// the typeof check is just to reduce client error noise
|
||||
body = '/**/ typeof ' + callback + ' === \'function\' && ' + callback + '(' + body + ');';
|
||||
}
|
||||
|
||||
return this.send(body);
|
||||
};
|
||||
|
||||
var jsonpDeprecated = deprecate(res.json,
|
||||
'res.jsonp(obj, status): Use res.jsonp(status, obj) instead');
|
||||
|
||||
var jsonpNumDeprecated = deprecate(res.json,
|
||||
'res.jsonp(num, status): Use res.status(status).jsonp(num) instead');
|
||||
|
||||
/**
|
||||
* Transfer the file at the given `path`.
|
||||
*
|
||||
@@ -297,8 +310,11 @@ var jsonpNumDeprecated = deprecate(res.json,
|
||||
*
|
||||
* Options:
|
||||
*
|
||||
* - `maxAge` defaulting to 0
|
||||
* - `root` root directory for relative filenames
|
||||
* - `maxAge` defaulting to 0
|
||||
* - `root` root directory for relative filenames
|
||||
* - `dotfiles` serve dotfiles, defaulting to false; can be `"allow"` to send them
|
||||
*
|
||||
* Other options are passed along to `send`.
|
||||
*
|
||||
* Examples:
|
||||
*
|
||||
@@ -374,9 +390,7 @@ res.sendfile = function(path, options, fn){
|
||||
}
|
||||
|
||||
// transfer
|
||||
var file = send(req, path);
|
||||
if (options.root) file.root(options.root);
|
||||
file.maxage(options.maxAge || 0);
|
||||
var file = send(req, path, options);
|
||||
file.on('error', error);
|
||||
file.on('directory', next);
|
||||
file.on('stream', stream);
|
||||
@@ -400,15 +414,17 @@ res.sendfile = function(path, options, fn){
|
||||
* @api public
|
||||
*/
|
||||
|
||||
res.download = function(path, filename, fn){
|
||||
res.download = function download(path, filename, fn) {
|
||||
// support function as second arg
|
||||
if ('function' == typeof filename) {
|
||||
if (typeof filename === 'function') {
|
||||
fn = filename;
|
||||
filename = null;
|
||||
}
|
||||
|
||||
filename = filename || path;
|
||||
this.set('Content-Disposition', 'attachment; filename="' + basename(filename) + '"');
|
||||
|
||||
this.set('Content-Disposition', contentDisposition(filename));
|
||||
|
||||
return this.sendfile(path, fn);
|
||||
};
|
||||
|
||||
@@ -531,11 +547,13 @@ res.format = function(obj){
|
||||
* @api public
|
||||
*/
|
||||
|
||||
res.attachment = function(filename){
|
||||
if (filename) this.type(extname(filename));
|
||||
this.set('Content-Disposition', filename
|
||||
? 'attachment; filename="' + basename(filename) + '"'
|
||||
: 'attachment');
|
||||
res.attachment = function attachment(filename) {
|
||||
if (filename) {
|
||||
this.type(extname(filename));
|
||||
}
|
||||
|
||||
this.set('Content-Disposition', contentDisposition(filename));
|
||||
|
||||
return this;
|
||||
};
|
||||
|
||||
@@ -595,7 +613,7 @@ res.get = function(field){
|
||||
res.clearCookie = function(name, options){
|
||||
var opts = { expires: new Date(1), path: '/' };
|
||||
return this.cookie(name, '', options
|
||||
? utils.merge(opts, options)
|
||||
? merge(opts, options)
|
||||
: opts);
|
||||
};
|
||||
|
||||
@@ -623,7 +641,7 @@ res.clearCookie = function(name, options){
|
||||
*/
|
||||
|
||||
res.cookie = function(name, val, options){
|
||||
options = utils.merge({}, options);
|
||||
options = merge({}, options);
|
||||
var secret = this.req.secret;
|
||||
var signed = options.signed;
|
||||
if (signed && !secret) throw new Error('connect.cookieParser("secret") required for signed cookies');
|
||||
@@ -681,7 +699,7 @@ res.location = function(url){
|
||||
if (!~url.indexOf('://') && 0 != url.indexOf('//')) {
|
||||
// relative to path
|
||||
if ('.' == url[0]) {
|
||||
path = req.originalUrl.split('?')[0];
|
||||
path = parseUrl.original(req).pathname;
|
||||
path = path + ('/' == path[path.length - 1] ? '' : '/');
|
||||
url = resolve(path, url);
|
||||
// relative to mount-point
|
||||
@@ -709,11 +727,8 @@ res.location = function(url){
|
||||
* res.redirect('/foo/bar');
|
||||
* res.redirect('http://example.com');
|
||||
* res.redirect(301, 'http://example.com');
|
||||
* res.redirect('http://example.com', 301);
|
||||
* res.redirect('../login'); // /blog/post/1 -> /blog/login
|
||||
*
|
||||
* @param {String} url
|
||||
* @param {Number} code
|
||||
* @api public
|
||||
*/
|
||||
|
||||
@@ -728,6 +743,7 @@ res.redirect = function(url){
|
||||
status = url;
|
||||
url = arguments[1];
|
||||
} else {
|
||||
deprecate('res.redirect(url, status): Use res.redirect(status, url) instead');
|
||||
status = arguments[1];
|
||||
}
|
||||
}
|
||||
@@ -743,7 +759,7 @@ res.redirect = function(url){
|
||||
},
|
||||
|
||||
html: function(){
|
||||
var u = utils.escape(url);
|
||||
var u = escapeHtml(url);
|
||||
body = '<p>' + statusCodes[status] + '. Redirecting to <a href="' + u + '">' + u + '</a></p>';
|
||||
},
|
||||
|
||||
@@ -768,31 +784,12 @@ res.redirect = function(url){
|
||||
*/
|
||||
|
||||
res.vary = function(field){
|
||||
var self = this;
|
||||
|
||||
// nothing
|
||||
// checks for back-compat
|
||||
if (!field) return this;
|
||||
if (Array.isArray(field) && !field.length) return this;
|
||||
|
||||
// array
|
||||
if (Array.isArray(field)) {
|
||||
field.forEach(function(field){
|
||||
self.vary(field);
|
||||
});
|
||||
return;
|
||||
}
|
||||
vary(this, field);
|
||||
|
||||
var vary = this.get('Vary');
|
||||
|
||||
// append
|
||||
if (vary) {
|
||||
vary = vary.split(/ *, */);
|
||||
if (!~vary.indexOf(field)) vary.push(field);
|
||||
this.set('Vary', vary.join(', '));
|
||||
return this;
|
||||
}
|
||||
|
||||
// set
|
||||
this.set('Vary', field);
|
||||
return this;
|
||||
};
|
||||
|
||||
|
||||
136
lib/utils.js
136
lib/utils.js
@@ -3,10 +3,10 @@
|
||||
* Module dependencies.
|
||||
*/
|
||||
|
||||
var mime = require('connect').mime
|
||||
, deprecate = require('util').deprecate
|
||||
, proxyaddr = require('proxy-addr')
|
||||
, crc32 = require('buffer-crc32');
|
||||
var etag = require('etag');
|
||||
var mime = require('connect').mime;
|
||||
var proxyaddr = require('proxy-addr');
|
||||
var typer = require('media-typer');
|
||||
|
||||
/**
|
||||
* toString ref.
|
||||
@@ -15,44 +15,37 @@ var mime = require('connect').mime
|
||||
var toString = {}.toString;
|
||||
|
||||
/**
|
||||
* Simple detection of charset parameter in content-type
|
||||
*/
|
||||
var charsetRegExp = /;\s*charset\s*=/;
|
||||
|
||||
/**
|
||||
* Deprecate function, like core `util.deprecate`,
|
||||
* but with NODE_ENV and color support.
|
||||
*
|
||||
* @param {Function} fn
|
||||
* @param {String} msg
|
||||
* @return {Function}
|
||||
* @api private
|
||||
*/
|
||||
|
||||
exports.deprecate = function(fn, msg){
|
||||
if (process.env.NODE_ENV === 'test') return fn;
|
||||
|
||||
// prepend module name
|
||||
msg = 'express: ' + msg;
|
||||
|
||||
if (process.stderr.isTTY) {
|
||||
// colorize
|
||||
msg = '\x1b[31;1m' + msg + '\x1b[0m';
|
||||
}
|
||||
|
||||
return deprecate(fn, msg);
|
||||
};
|
||||
|
||||
/**
|
||||
* Return ETag for `body`.
|
||||
* Return strong ETag for `body`.
|
||||
*
|
||||
* @param {String|Buffer} body
|
||||
* @param {String} [encoding]
|
||||
* @return {String}
|
||||
* @api private
|
||||
*/
|
||||
|
||||
exports.etag = function(body){
|
||||
return '"' + crc32.signed(body) + '"';
|
||||
exports.etag = function (body, encoding) {
|
||||
var buf = !Buffer.isBuffer(body)
|
||||
? new Buffer(body, encoding)
|
||||
: body;
|
||||
|
||||
return etag(buf, {weak: false});
|
||||
};
|
||||
|
||||
/**
|
||||
* Return weak ETag for `body`.
|
||||
*
|
||||
* @param {String|Buffer} body
|
||||
* @param {String} [encoding]
|
||||
* @return {String}
|
||||
* @api private
|
||||
*/
|
||||
|
||||
exports.wetag = function wetag(body, encoding){
|
||||
var buf = !Buffer.isBuffer(body)
|
||||
? new Buffer(body, encoding)
|
||||
: body;
|
||||
|
||||
return etag(buf, {weak: true});
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -289,22 +282,6 @@ function acceptParams(str, index) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* Escape special characters in the given string of html.
|
||||
*
|
||||
* @param {String} html
|
||||
* @return {String}
|
||||
* @api private
|
||||
*/
|
||||
|
||||
exports.escape = function(html) {
|
||||
return String(html)
|
||||
.replace(/&/g, '&')
|
||||
.replace(/"/g, '"')
|
||||
.replace(/</g, '<')
|
||||
.replace(/>/g, '>');
|
||||
};
|
||||
|
||||
/**
|
||||
* Normalize the given path string,
|
||||
* returning a regular expression.
|
||||
@@ -344,6 +321,40 @@ exports.pathRegexp = function(path, keys, sensitive, strict) {
|
||||
return new RegExp('^' + path + '$', sensitive ? '' : 'i');
|
||||
}
|
||||
|
||||
/**
|
||||
* Compile "etag" value to function.
|
||||
*
|
||||
* @param {Boolean|String|Function} val
|
||||
* @return {Function}
|
||||
* @api private
|
||||
*/
|
||||
|
||||
exports.compileETag = function(val) {
|
||||
var fn;
|
||||
|
||||
if (typeof val === 'function') {
|
||||
return val;
|
||||
}
|
||||
|
||||
switch (val) {
|
||||
case true:
|
||||
fn = exports.wetag;
|
||||
break;
|
||||
case false:
|
||||
break;
|
||||
case 'strong':
|
||||
fn = exports.etag;
|
||||
break;
|
||||
case 'weak':
|
||||
fn = exports.wetag;
|
||||
break;
|
||||
default:
|
||||
throw new TypeError('unknown value for etag function: ' + val);
|
||||
}
|
||||
|
||||
return fn;
|
||||
}
|
||||
|
||||
/**
|
||||
* Compile "proxy trust" value to function.
|
||||
*
|
||||
@@ -385,21 +396,12 @@ exports.compileTrust = function(val) {
|
||||
exports.setCharset = function(type, charset){
|
||||
if (!type || !charset) return type;
|
||||
|
||||
var exists = charsetRegExp.test(type);
|
||||
// parse type
|
||||
var parsed = typer.parse(type);
|
||||
|
||||
// removing existing charset
|
||||
if (exists) {
|
||||
var parts = type.split(';');
|
||||
// set charset
|
||||
parsed.parameters.charset = charset;
|
||||
|
||||
for (var i = 1; i < parts.length; i++) {
|
||||
if (charsetRegExp.test(';' + parts[i])) {
|
||||
parts.splice(i, 1);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
type = parts.join(';');
|
||||
}
|
||||
|
||||
return type + '; charset=' + charset;
|
||||
// format type
|
||||
return typer.format(parsed);
|
||||
};
|
||||
|
||||
97
package.json
97
package.json
@@ -1,38 +1,19 @@
|
||||
{
|
||||
"name": "express",
|
||||
"description": "Sinatra inspired web development framework",
|
||||
"version": "3.8.0",
|
||||
"version": "3.18.4",
|
||||
"author": "TJ Holowaychuk <tj@vision-media.ca>",
|
||||
"contributors": [
|
||||
{
|
||||
"name": "TJ Holowaychuk",
|
||||
"email": "tj@vision-media.ca"
|
||||
},
|
||||
{
|
||||
"name": "Aaron Heckmann",
|
||||
"email": "aaron.heckmann+github@gmail.com"
|
||||
},
|
||||
{
|
||||
"name": "Ciaran Jessup",
|
||||
"email": "ciaranj@gmail.com"
|
||||
},
|
||||
{
|
||||
"name": "Douglas Christopher Wilson",
|
||||
"email": "doug@somethingdoug.com"
|
||||
},
|
||||
{
|
||||
"name": "Guillermo Rauch",
|
||||
"email": "rauchg@gmail.com"
|
||||
},
|
||||
{
|
||||
"name": "Jonathan Ong",
|
||||
"email": "me@jongleberry.com"
|
||||
},
|
||||
{
|
||||
"name": "Roman Shtylman",
|
||||
"email": "shtylman+expressjs@gmail.com"
|
||||
}
|
||||
"Aaron Heckmann <aaron.heckmann+github@gmail.com>",
|
||||
"Ciaran Jessup <ciaranj@gmail.com>",
|
||||
"Douglas Christopher Wilson <doug@somethingdoug.com>",
|
||||
"Guillermo Rauch <rauchg@gmail.com>",
|
||||
"Jonathan Ong <me@jongleberry.com>",
|
||||
"Roman Shtylman <shtylman+expressjs@gmail.com"
|
||||
],
|
||||
"license": "MIT",
|
||||
"repository": "strongloop/express",
|
||||
"homepage": "http://expressjs.com/",
|
||||
"keywords": [
|
||||
"express",
|
||||
"framework",
|
||||
@@ -44,35 +25,39 @@
|
||||
"app",
|
||||
"api"
|
||||
],
|
||||
"repository": "git://github.com/visionmedia/express",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"connect": "2.17.1",
|
||||
"basic-auth": "1.0.0",
|
||||
"connect": "2.27.4",
|
||||
"content-disposition": "0.5.0",
|
||||
"commander": "1.3.2",
|
||||
"methods": "1.0.0",
|
||||
"cookie-signature": "1.0.5",
|
||||
"debug": "~2.1.0",
|
||||
"depd": "~1.0.0",
|
||||
"escape-html": "1.0.1",
|
||||
"etag": "~1.5.1",
|
||||
"fresh": "0.2.4",
|
||||
"media-typer": "0.3.0",
|
||||
"methods": "1.1.0",
|
||||
"mkdirp": "0.5.0",
|
||||
"parseurl": "1.0.1",
|
||||
"proxy-addr": "1.0.0",
|
||||
"range-parser": "1.0.0",
|
||||
"parseurl": "~1.3.0",
|
||||
"proxy-addr": "~1.0.4",
|
||||
"range-parser": "~1.0.2",
|
||||
"send": "0.10.1",
|
||||
"utils-merge": "1.0.0",
|
||||
"vary": "~1.0.0",
|
||||
"cookie": "0.1.2",
|
||||
"buffer-crc32": "0.2.1",
|
||||
"fresh": "0.2.2",
|
||||
"send": "0.3.0",
|
||||
"cookie-signature": "1.0.3",
|
||||
"merge-descriptors": "0.0.2",
|
||||
"debug": ">= 0.8.0 < 1"
|
||||
"merge-descriptors": "0.0.2"
|
||||
},
|
||||
"devDependencies": {
|
||||
"ejs": "~0.8.4",
|
||||
"istanbul": "0.2.10",
|
||||
"mocha": "~1.19.0",
|
||||
"should": "~3.3.1",
|
||||
"jade": "~0.30.0",
|
||||
"connect-redis": "~1.5.0",
|
||||
"istanbul": "0.3.2",
|
||||
"mocha": "~2.0.0",
|
||||
"should": "~4.3.0",
|
||||
"supertest": "~0.15.0",
|
||||
"ejs": "~1.0.0",
|
||||
"jade": "~1.7.0",
|
||||
"hjs": "~0.0.6",
|
||||
"stylus": "~0.40.0",
|
||||
"connect-redis": "~1.4.5",
|
||||
"marked": "0.2.10",
|
||||
"supertest": "~0.12.1"
|
||||
"marked": "0.3.2"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 0.8.0"
|
||||
@@ -80,10 +65,18 @@
|
||||
"bin": {
|
||||
"express": "./bin/express"
|
||||
},
|
||||
"files": [
|
||||
"LICENSE",
|
||||
"History.md",
|
||||
"Readme.md",
|
||||
"index.js",
|
||||
"bin/",
|
||||
"lib/"
|
||||
],
|
||||
"scripts": {
|
||||
"prepublish": "npm prune",
|
||||
"test": "mocha --require test/support/env --reporter dot --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/",
|
||||
"test-travis": "istanbul cover node_modules/mocha/bin/_mocha --report lcovonly -- --require test/support/env --reporter spec --check-leaks test/ test/acceptance/"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -7,14 +7,11 @@ describe('ejs', function(){
|
||||
it('should respond with html', function(done){
|
||||
request(app)
|
||||
.get('/')
|
||||
.end(function(err, res){
|
||||
res.should.have.status(200);
|
||||
res.should.have.header('Content-Type', 'text/html; charset=utf-8');
|
||||
res.text.should.include('<li>tobi <tobi@learnboost.com></li>');
|
||||
res.text.should.include('<li>loki <loki@learnboost.com></li>');
|
||||
res.text.should.include('<li>jane <jane@learnboost.com></li>');
|
||||
done();
|
||||
});
|
||||
.expect('Content-Type', 'text/html; charset=utf-8')
|
||||
.expect(/<li>tobi <tobi@learnboost\.com><\/li>/)
|
||||
.expect(/<li>loki <loki@learnboost\.com><\/li>/)
|
||||
.expect(/<li>jane <jane@learnboost\.com><\/li>/)
|
||||
.expect(200, done)
|
||||
})
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
|
||||
var app = require('../../examples/markdown')
|
||||
, request = require('supertest');
|
||||
var request = require('supertest')
|
||||
|
||||
describe('markdown', function(){
|
||||
describe('GET /', function(){
|
||||
@@ -18,4 +18,4 @@ describe('markdown', function(){
|
||||
.expect(500,done)
|
||||
})
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
@@ -33,6 +33,7 @@ describe('mvc', function(){
|
||||
it('should update the pet', function(done){
|
||||
request(app)
|
||||
.put('/pet/3')
|
||||
.set('Content-Type', 'application/x-www-form-urlencoded')
|
||||
.send({ pet: { name: 'Boots' } })
|
||||
.end(function(err, res){
|
||||
if (err) return done(err);
|
||||
@@ -47,13 +48,11 @@ describe('mvc', function(){
|
||||
it('should display a list of users', function(done){
|
||||
request(app)
|
||||
.get('/users')
|
||||
.end(function(err, res){
|
||||
res.text.should.include('<h1>Users</h1>');
|
||||
res.text.should.include('>TJ<');
|
||||
res.text.should.include('>Guillermo<');
|
||||
res.text.should.include('>Nathan<');
|
||||
done();
|
||||
})
|
||||
.expect(/<h1>Users<\/h1>/)
|
||||
.expect(/>TJ</)
|
||||
.expect(/>Guillermo</)
|
||||
.expect(/>Nathan</)
|
||||
.expect(200, done)
|
||||
})
|
||||
})
|
||||
|
||||
@@ -62,21 +61,16 @@ describe('mvc', function(){
|
||||
it('should display the user', function(done){
|
||||
request(app)
|
||||
.get('/user/0')
|
||||
.end(function(err, res){
|
||||
res.text.should.include('<h1>TJ <a href="/user/0/edit">edit');
|
||||
done();
|
||||
})
|
||||
.expect(200, /<h1>TJ <a href="\/user\/0\/edit">edit/, done)
|
||||
})
|
||||
|
||||
it('should display the users pets', function(done){
|
||||
request(app)
|
||||
.get('/user/0')
|
||||
.end(function(err, res){
|
||||
res.text.should.include('/pet/0">Tobi');
|
||||
res.text.should.include('/pet/1">Loki');
|
||||
res.text.should.include('/pet/2">Jane');
|
||||
done();
|
||||
})
|
||||
.expect(/\/pet\/0">Tobi/)
|
||||
.expect(/\/pet\/1">Loki/)
|
||||
.expect(/\/pet\/2">Jane/)
|
||||
.expect(200, done)
|
||||
})
|
||||
})
|
||||
|
||||
@@ -102,6 +96,7 @@ describe('mvc', function(){
|
||||
it('should update the user', function(done){
|
||||
request(app)
|
||||
.put('/user/1')
|
||||
.set('Content-Type', 'application/x-www-form-urlencoded')
|
||||
.send({ user: { name: 'Tobo' }})
|
||||
.end(function(err, res){
|
||||
if (err) return done(err);
|
||||
@@ -116,6 +111,7 @@ describe('mvc', function(){
|
||||
it('should create a pet for user', function(done){
|
||||
request(app)
|
||||
.post('/user/2/pet')
|
||||
.set('Content-Type', 'application/x-www-form-urlencoded')
|
||||
.send({ pet: { name: 'Snickers' }})
|
||||
.expect('Location', '/user/2')
|
||||
.expect(302, function(err, res){
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
var app = require('../../examples/params/app')
|
||||
, request = require('supertest');
|
||||
var request = require('supertest')
|
||||
|
||||
describe('params', function(){
|
||||
describe('GET /', function(){
|
||||
@@ -18,6 +18,14 @@ describe('params', function(){
|
||||
})
|
||||
})
|
||||
|
||||
describe('GET /user/9', function(){
|
||||
it('should fail to find user', function(done){
|
||||
request(app)
|
||||
.get('/user/9')
|
||||
.expect(/failed to find user/,done)
|
||||
})
|
||||
})
|
||||
|
||||
describe('GET /users/0-2', function(){
|
||||
it('should respond with three users', function(done){
|
||||
request(app)
|
||||
@@ -25,4 +33,12 @@ describe('params', function(){
|
||||
.expect(/users tj, tobi/,done)
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
describe('GET /users/foo-bar', function(){
|
||||
it('should fail integer parsing', function(done){
|
||||
request(app)
|
||||
.get('/users/foo-bar')
|
||||
.expect(/failed to parseInt foo/,done)
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
var app = require('../../examples/resource/app')
|
||||
, request = require('supertest');
|
||||
var request = require('supertest')
|
||||
|
||||
describe('resource', function(){
|
||||
describe('GET /', function(){
|
||||
@@ -26,6 +26,14 @@ describe('resource', function(){
|
||||
})
|
||||
})
|
||||
|
||||
describe('GET /users/9', function(){
|
||||
it('should respond with error', function(done){
|
||||
request(app)
|
||||
.get('/users/9')
|
||||
.expect('{"error":"Cannot find user"}', done)
|
||||
})
|
||||
})
|
||||
|
||||
describe('GET /users/1..3', function(){
|
||||
it('should respond with users 1 through 3', function(done){
|
||||
request(app)
|
||||
@@ -35,13 +43,21 @@ describe('resource', function(){
|
||||
})
|
||||
|
||||
describe('DELETE /users/1', function(){
|
||||
it('should respond with users 1 through 3', function(done){
|
||||
it('should delete user 1', function(done){
|
||||
request(app)
|
||||
.del('/users/1')
|
||||
.expect(/^destroyed/,done)
|
||||
})
|
||||
})
|
||||
|
||||
describe('DELETE /users/9', function(){
|
||||
it('should fail', function(done){
|
||||
request(app)
|
||||
.del('/users/9')
|
||||
.expect('Cannot find user', done)
|
||||
})
|
||||
})
|
||||
|
||||
describe('GET /users/1..3.json', function(){
|
||||
it('should respond with users 2 and 3 as json', function(done){
|
||||
request(app)
|
||||
@@ -49,4 +65,4 @@ describe('resource', function(){
|
||||
.expect(/^\[null,{"name":"aaron"},{"name":"guillermo"}\]/,done)
|
||||
})
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
@@ -53,7 +53,7 @@ describe('web-service', function(){
|
||||
.get('/api/repos?api-key=foo')
|
||||
.expect('Content-Type', 'application/json; charset=utf-8')
|
||||
.expect(/"name":"express"/)
|
||||
.expect(/"url":"http:\/\/github.com\/visionmedia\/express"/)
|
||||
.expect(/"url":"http:\/\/github.com\/strongloop\/express"/)
|
||||
.expect(200, done)
|
||||
})
|
||||
})
|
||||
@@ -98,12 +98,8 @@ describe('web-service', function(){
|
||||
it('should respond with 404 json', function(done){
|
||||
request(app)
|
||||
.get('/api/something?api-key=bar')
|
||||
.end(function(err, res){
|
||||
res.should.have.status(404);
|
||||
res.should.be.json;
|
||||
res.text.should.equal('{"error":"Lame, can\'t find that"}');
|
||||
done();
|
||||
});
|
||||
.expect('Content-Type', /json/)
|
||||
.expect(404, '{"error":"Lame, can\'t find that"}', done)
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
@@ -16,6 +16,31 @@ describe('HEAD', function(){
|
||||
.head('/tobi')
|
||||
.expect(200, done);
|
||||
})
|
||||
|
||||
it('should output the same headers as GET requests', function(done){
|
||||
var app = express();
|
||||
|
||||
app.get('/tobi', function(req, res){
|
||||
// send() detects HEAD
|
||||
res.send('tobi');
|
||||
});
|
||||
|
||||
request(app)
|
||||
.get('/tobi')
|
||||
.expect(200, function(err, res){
|
||||
if (err) return done(err);
|
||||
var headers = res.headers;
|
||||
request(app)
|
||||
.get('/tobi')
|
||||
.expect(200, function(err, res){
|
||||
if (err) return done(err);
|
||||
delete headers.date;
|
||||
delete res.headers.date;
|
||||
assert.deepEqual(res.headers, headers);
|
||||
done();
|
||||
});
|
||||
});
|
||||
})
|
||||
})
|
||||
|
||||
describe('app.head()', function(){
|
||||
|
||||
@@ -101,6 +101,24 @@ describe('app', function(){
|
||||
.expect('123', done);
|
||||
})
|
||||
|
||||
it('should work with encoded values', function(done){
|
||||
var app = express();
|
||||
|
||||
app.param('name', function(req, res, next, name){
|
||||
req.params.name = name;
|
||||
next();
|
||||
});
|
||||
|
||||
app.get('/user/:name', function(req, res){
|
||||
var name = req.params.name;
|
||||
res.send('' + name);
|
||||
});
|
||||
|
||||
request(app)
|
||||
.get('/user/foo%25bar')
|
||||
.expect('foo%bar', done);
|
||||
})
|
||||
|
||||
it('should catch thrown error', function(done){
|
||||
var app = express();
|
||||
|
||||
|
||||
@@ -95,7 +95,7 @@ describe('app', function(){
|
||||
app.render('user.jade', function(err, str){
|
||||
// nextTick to prevent cyclic
|
||||
process.nextTick(function(){
|
||||
err.message.should.match(/user is not defined/);
|
||||
err.message.should.match(/Cannot read property 'name' of undefined/);
|
||||
done();
|
||||
});
|
||||
})
|
||||
|
||||
@@ -564,6 +564,30 @@ describe('app.router', function(){
|
||||
})
|
||||
})
|
||||
|
||||
describe('when next("route") is called', function(){
|
||||
it('should jump to next route', function(done){
|
||||
var app = express()
|
||||
|
||||
function fn(req, res, next){
|
||||
res.set('X-Hit', '1')
|
||||
next('route')
|
||||
}
|
||||
|
||||
app.get('/foo', fn, function(req, res, next){
|
||||
res.end('failure')
|
||||
});
|
||||
|
||||
app.get('/foo', function(req, res){
|
||||
res.end('success')
|
||||
})
|
||||
|
||||
request(app)
|
||||
.get('/foo')
|
||||
.expect('X-Hit', '1')
|
||||
.expect(200, 'success', done)
|
||||
})
|
||||
})
|
||||
|
||||
describe('when next(err) is called', function(){
|
||||
it('should break out of app.router', function(done){
|
||||
var app = express()
|
||||
|
||||
@@ -13,6 +13,29 @@ describe('config', function(){
|
||||
var app = express();
|
||||
app.set('foo', undefined).should.equal(app);
|
||||
})
|
||||
|
||||
describe('"etag"', function(){
|
||||
it('should throw on bad value', function(){
|
||||
var app = express()
|
||||
app.set.bind(app, 'etag', 42).should.throw(/unknown value/)
|
||||
})
|
||||
|
||||
it('should set "etag fn"', function(){
|
||||
var app = express()
|
||||
var fn = function(){}
|
||||
app.set('etag', fn)
|
||||
app.get('etag fn').should.equal(fn)
|
||||
})
|
||||
})
|
||||
|
||||
describe('"trust proxy"', function(){
|
||||
it('should set "trust proxy fn"', function(){
|
||||
var app = express()
|
||||
var fn = function(){}
|
||||
app.set('trust proxy', fn)
|
||||
app.get('trust proxy fn').should.equal(fn)
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
describe('.get()', function(){
|
||||
@@ -91,4 +114,4 @@ describe('config', function(){
|
||||
app.disabled('foo').should.be.false;
|
||||
})
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
1
test/fixtures/.name
vendored
Normal file
1
test/fixtures/.name
vendored
Normal file
@@ -0,0 +1 @@
|
||||
tobi
|
||||
1
test/fixtures/blog/index.html
vendored
Normal file
1
test/fixtures/blog/index.html
vendored
Normal file
@@ -0,0 +1 @@
|
||||
<b>index</b>
|
||||
@@ -6,15 +6,16 @@ describe('req', function(){
|
||||
describe('.fresh', function(){
|
||||
it('should return true when the resource is not modified', function(done){
|
||||
var app = express();
|
||||
var etag = '"12345"';
|
||||
|
||||
app.use(function(req, res){
|
||||
res.set('ETag', '12345');
|
||||
res.set('ETag', etag);
|
||||
res.send(req.fresh);
|
||||
});
|
||||
|
||||
request(app)
|
||||
.get('/')
|
||||
.set('If-None-Match', '12345')
|
||||
.set('If-None-Match', etag)
|
||||
.expect(304, done);
|
||||
})
|
||||
|
||||
@@ -22,14 +23,14 @@ describe('req', function(){
|
||||
var app = express();
|
||||
|
||||
app.use(function(req, res){
|
||||
res.set('ETag', '123');
|
||||
res.set('ETag', '"123"');
|
||||
res.send(req.fresh);
|
||||
});
|
||||
|
||||
request(app)
|
||||
.get('/')
|
||||
.set('If-None-Match', '12345')
|
||||
.expect('false', done);
|
||||
.set('If-None-Match', '"12345"')
|
||||
.expect(200, 'false', done);
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
@@ -45,10 +45,9 @@ describe('req', function(){
|
||||
res.send(req.ip);
|
||||
});
|
||||
|
||||
request(app)
|
||||
.get('/')
|
||||
.set('X-Forwarded-For', 'client, p1, p2')
|
||||
.expect('127.0.0.1', done);
|
||||
var test = request(app).get('/')
|
||||
test.set('X-Forwarded-For', 'client, p1, p2')
|
||||
test.expect(200, getExpectedClientAddress(test._server), done);
|
||||
})
|
||||
})
|
||||
})
|
||||
@@ -63,10 +62,19 @@ describe('req', function(){
|
||||
res.send(req.ip);
|
||||
});
|
||||
|
||||
request(app)
|
||||
.get('/')
|
||||
.expect('127.0.0.1', done);
|
||||
var test = request(app).get('/')
|
||||
test.expect(200, getExpectedClientAddress(test._server), done);
|
||||
})
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
/**
|
||||
* Get the local client address depending on AF_NET of server
|
||||
*/
|
||||
|
||||
function getExpectedClientAddress(server) {
|
||||
return server.address().address === '::'
|
||||
? '::ffff:127.0.0.1'
|
||||
: '127.0.0.1';
|
||||
}
|
||||
|
||||
@@ -32,6 +32,21 @@ describe('req', function(){
|
||||
.expect('https', done);
|
||||
})
|
||||
|
||||
it('should default to the socket addr if X-Forwarded-Proto not present', function(done){
|
||||
var app = express();
|
||||
|
||||
app.enable('trust proxy');
|
||||
|
||||
app.use(function(req, res){
|
||||
req.connection.encrypted = true;
|
||||
res.end(req.protocol);
|
||||
});
|
||||
|
||||
request(app)
|
||||
.get('/')
|
||||
.expect('https', done);
|
||||
})
|
||||
|
||||
it('should ignore X-Forwarded-Proto if socket addr not trusted', function(done){
|
||||
var app = express();
|
||||
|
||||
|
||||
@@ -6,15 +6,16 @@ describe('req', function(){
|
||||
describe('.stale', function(){
|
||||
it('should return false when the resource is not modified', function(done){
|
||||
var app = express();
|
||||
var etag = '"12345"';
|
||||
|
||||
app.use(function(req, res){
|
||||
res.set('ETag', '12345');
|
||||
res.set('ETag', etag);
|
||||
res.send(req.stale);
|
||||
});
|
||||
|
||||
request(app)
|
||||
.get('/')
|
||||
.set('If-None-Match', '12345')
|
||||
.set('If-None-Match', etag)
|
||||
.expect(304, done);
|
||||
})
|
||||
|
||||
@@ -22,14 +23,14 @@ describe('req', function(){
|
||||
var app = express();
|
||||
|
||||
app.use(function(req, res){
|
||||
res.set('ETag', '123');
|
||||
res.set('ETag', '"123"');
|
||||
res.send(req.stale);
|
||||
});
|
||||
|
||||
request(app)
|
||||
.get('/')
|
||||
.set('If-None-Match', '12345')
|
||||
.expect('true', done);
|
||||
.set('If-None-Match', '"12345"')
|
||||
.expect(200, 'true', done);
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
@@ -15,7 +15,33 @@ describe('req', function(){
|
||||
request(app)
|
||||
.get('/')
|
||||
.set('Host', 'tobi.ferrets.example.com')
|
||||
.expect(["ferrets","tobi"], done);
|
||||
.expect(200, ['ferrets', 'tobi'], done);
|
||||
})
|
||||
|
||||
it('should work with IPv4 address', function(done){
|
||||
var app = express();
|
||||
|
||||
app.use(function(req, res){
|
||||
res.send(req.subdomains);
|
||||
});
|
||||
|
||||
request(app)
|
||||
.get('/')
|
||||
.set('Host', '127.0.0.1')
|
||||
.expect(200, [], done);
|
||||
})
|
||||
|
||||
it('should work with IPv6 address', function(done){
|
||||
var app = express();
|
||||
|
||||
app.use(function(req, res){
|
||||
res.send(req.subdomains);
|
||||
});
|
||||
|
||||
request(app)
|
||||
.get('/')
|
||||
.set('Host', '[::1]')
|
||||
.expect(200, [], done);
|
||||
})
|
||||
})
|
||||
|
||||
@@ -30,7 +56,7 @@ describe('req', function(){
|
||||
request(app)
|
||||
.get('/')
|
||||
.set('Host', 'example.com')
|
||||
.expect([], done);
|
||||
.expect(200, [], done);
|
||||
})
|
||||
})
|
||||
|
||||
@@ -45,7 +71,23 @@ describe('req', function(){
|
||||
|
||||
request(app)
|
||||
.get('/')
|
||||
.expect([], done);
|
||||
.expect(200, [], done);
|
||||
})
|
||||
})
|
||||
|
||||
describe('with trusted X-Forwarded-Host', function () {
|
||||
it('should return an array', function (done) {
|
||||
var app = express();
|
||||
|
||||
app.set('trust proxy', true);
|
||||
app.use(function (req, res) {
|
||||
res.send(req.subdomains);
|
||||
});
|
||||
|
||||
request(app)
|
||||
.get('/')
|
||||
.set('X-Forwarded-Host', 'tobi.ferrets.example.com')
|
||||
.expect(200, ['ferrets', 'tobi'], done);
|
||||
})
|
||||
})
|
||||
|
||||
@@ -62,7 +104,35 @@ describe('req', function(){
|
||||
request(app)
|
||||
.get('/')
|
||||
.set('Host', 'tobi.ferrets.sub.example.com')
|
||||
.expect(["com","example","sub","ferrets","tobi"], done);
|
||||
.expect(200, ['com', 'example', 'sub', 'ferrets', 'tobi'], done);
|
||||
})
|
||||
|
||||
it('should return an array with the whole IPv4', function (done) {
|
||||
var app = express();
|
||||
app.set('subdomain offset', 0);
|
||||
|
||||
app.use(function(req, res){
|
||||
res.send(req.subdomains);
|
||||
});
|
||||
|
||||
request(app)
|
||||
.get('/')
|
||||
.set('Host', '127.0.0.1')
|
||||
.expect(200, ['127.0.0.1'], done);
|
||||
})
|
||||
|
||||
it('should return an array with the whole IPv6', function (done) {
|
||||
var app = express();
|
||||
app.set('subdomain offset', 0);
|
||||
|
||||
app.use(function(req, res){
|
||||
res.send(req.subdomains);
|
||||
});
|
||||
|
||||
request(app)
|
||||
.get('/')
|
||||
.set('Host', '[::1]')
|
||||
.expect(200, ['[::1]'], done);
|
||||
})
|
||||
})
|
||||
|
||||
@@ -78,7 +148,7 @@ describe('req', function(){
|
||||
request(app)
|
||||
.get('/')
|
||||
.set('Host', 'tobi.ferrets.sub.example.com')
|
||||
.expect(["ferrets","tobi"], done);
|
||||
.expect(200, ['ferrets', 'tobi'], done);
|
||||
})
|
||||
})
|
||||
|
||||
@@ -94,7 +164,7 @@ describe('req', function(){
|
||||
request(app)
|
||||
.get('/')
|
||||
.set('Host', 'sub.example.com')
|
||||
.expect([], done);
|
||||
.expect(200, [], done);
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
|
||||
var express = require('../')
|
||||
, request = require('supertest')
|
||||
, utils = require('connect').utils
|
||||
, cookie = require('cookie');
|
||||
var merge = require('utils-merge');
|
||||
|
||||
describe('res', function(){
|
||||
describe('.cookie(name, object)', function(){
|
||||
@@ -89,7 +89,7 @@ describe('res', function(){
|
||||
request(app)
|
||||
.get('/')
|
||||
.end(function(err, res){
|
||||
res.headers['set-cookie'][0].should.not.include('Thu, 01 Jan 1970 00:00:01 GMT');
|
||||
res.headers['set-cookie'][0].should.not.containEql('Thu, 01 Jan 1970 00:00:01 GMT');
|
||||
done();
|
||||
})
|
||||
})
|
||||
@@ -104,17 +104,14 @@ describe('res', function(){
|
||||
|
||||
request(app)
|
||||
.get('/')
|
||||
.end(function(err, res){
|
||||
res.headers['set-cookie'][0].should.include('Max-Age=1');
|
||||
done();
|
||||
})
|
||||
.expect('Set-Cookie', /Max-Age=1/, done)
|
||||
})
|
||||
|
||||
it('should not mutate the options object', function(done){
|
||||
var app = express();
|
||||
|
||||
var options = { maxAge: 1000 };
|
||||
var optionsCopy = utils.merge({}, options);
|
||||
var optionsCopy = merge({}, options);
|
||||
|
||||
app.use(function(req, res){
|
||||
res.cookie('name', 'tobi', options)
|
||||
|
||||
@@ -14,12 +14,9 @@ describe('res', function(){
|
||||
|
||||
request(app)
|
||||
.get('/')
|
||||
.end(function(err, res){
|
||||
res.should.have.header('Content-Type', 'text/html; charset=UTF-8');
|
||||
res.should.have.header('Content-Disposition', 'attachment; filename="user.html"');
|
||||
res.text.should.equal('<p>{{user.name}}</p>');
|
||||
done();
|
||||
});
|
||||
.expect('Content-Type', 'text/html; charset=UTF-8')
|
||||
.expect('Content-Disposition', 'attachment; filename="user.html"')
|
||||
.expect(200, '<p>{{user.name}}</p>', done)
|
||||
})
|
||||
})
|
||||
|
||||
@@ -33,11 +30,9 @@ describe('res', function(){
|
||||
|
||||
request(app)
|
||||
.get('/')
|
||||
.end(function(err, res){
|
||||
res.should.have.header('Content-Type', 'text/html; charset=UTF-8');
|
||||
res.should.have.header('Content-Disposition', 'attachment; filename="document"');
|
||||
done();
|
||||
});
|
||||
.expect('Content-Type', 'text/html; charset=UTF-8')
|
||||
.expect('Content-Disposition', 'attachment; filename="document"')
|
||||
.expect(200, done)
|
||||
})
|
||||
})
|
||||
|
||||
@@ -52,10 +47,11 @@ describe('res', function(){
|
||||
|
||||
request(app)
|
||||
.get('/')
|
||||
.end(function(err, res){
|
||||
res.should.have.header('Content-Type', 'text/html; charset=UTF-8');
|
||||
res.should.have.header('Content-Disposition', 'attachment; filename="user.html"');
|
||||
});
|
||||
.expect('Content-Type', 'text/html; charset=UTF-8')
|
||||
.expect('Content-Disposition', 'attachment; filename="user.html"')
|
||||
.expect(200, function(err){
|
||||
assert.ifError(err)
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
@@ -70,10 +66,11 @@ describe('res', function(){
|
||||
|
||||
request(app)
|
||||
.get('/')
|
||||
.end(function(err, res){
|
||||
res.should.have.header('Content-Type', 'text/html; charset=UTF-8');
|
||||
res.should.have.header('Content-Disposition', 'attachment; filename="document"');
|
||||
});
|
||||
.expect('Content-Type', 'text/html; charset=UTF-8')
|
||||
.expect('Content-Disposition', 'attachment; filename="document"')
|
||||
.expect(200, function(err){
|
||||
assert.ifError(err)
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
|
||||
@@ -14,11 +14,8 @@ describe('res', function(){
|
||||
|
||||
request(app)
|
||||
.get('/?callback=something')
|
||||
.end(function(err, res){
|
||||
res.headers.should.have.property('content-type', 'text/javascript; charset=utf-8');
|
||||
res.text.should.equal('typeof something === \'function\' && something({"count":1});');
|
||||
done();
|
||||
})
|
||||
.expect('Content-Type', 'text/javascript; charset=utf-8')
|
||||
.expect(200, /something\(\{"count":1\}\);/, done);
|
||||
})
|
||||
|
||||
it('should use first callback parameter with jsonp', function(done){
|
||||
@@ -29,12 +26,9 @@ describe('res', function(){
|
||||
});
|
||||
|
||||
request(app)
|
||||
.get('/?callback=something&callback=somethingelse')
|
||||
.end(function(err, res){
|
||||
res.headers.should.have.property('content-type', 'text/javascript; charset=utf-8');
|
||||
res.text.should.equal('typeof something === \'function\' && something({"count":1});');
|
||||
done();
|
||||
})
|
||||
.get('/?callback=something&callback=somethingelse')
|
||||
.expect('Content-Type', 'text/javascript; charset=utf-8')
|
||||
.expect(200, /something\(\{"count":1\}\);/, done);
|
||||
})
|
||||
|
||||
it('should ignore object callback parameter with jsonp', function(done){
|
||||
@@ -61,11 +55,8 @@ describe('res', function(){
|
||||
|
||||
request(app)
|
||||
.get('/?clb=something')
|
||||
.end(function(err, res){
|
||||
res.headers.should.have.property('content-type', 'text/javascript; charset=utf-8');
|
||||
res.text.should.equal('typeof something === \'function\' && something({"count":1});');
|
||||
done();
|
||||
})
|
||||
.expect('Content-Type', 'text/javascript; charset=utf-8')
|
||||
.expect(200, /something\(\{"count":1\}\);/, done);
|
||||
})
|
||||
|
||||
it('should allow []', function(done){
|
||||
@@ -77,11 +68,8 @@ describe('res', function(){
|
||||
|
||||
request(app)
|
||||
.get('/?callback=callbacks[123]')
|
||||
.end(function(err, res){
|
||||
res.headers.should.have.property('content-type', 'text/javascript; charset=utf-8');
|
||||
res.text.should.equal('typeof callbacks[123] === \'function\' && callbacks[123]({"count":1});');
|
||||
done();
|
||||
})
|
||||
.expect('Content-Type', 'text/javascript; charset=utf-8')
|
||||
.expect(200, /callbacks\[123\]\(\{"count":1\}\);/, done);
|
||||
})
|
||||
|
||||
it('should disallow arbitrary js', function(done){
|
||||
@@ -93,11 +81,8 @@ describe('res', function(){
|
||||
|
||||
request(app)
|
||||
.get('/?callback=foo;bar()')
|
||||
.end(function(err, res){
|
||||
res.headers.should.have.property('content-type', 'text/javascript; charset=utf-8');
|
||||
res.text.should.equal('typeof foobar === \'function\' && foobar({});');
|
||||
done();
|
||||
})
|
||||
.expect('Content-Type', 'text/javascript; charset=utf-8')
|
||||
.expect(200, /foobar\(\{\}\);/, done);
|
||||
})
|
||||
|
||||
it('should escape utf whitespace', function(done){
|
||||
@@ -109,13 +94,37 @@ describe('res', function(){
|
||||
|
||||
request(app)
|
||||
.get('/?callback=foo')
|
||||
.end(function(err, res){
|
||||
res.headers.should.have.property('content-type', 'text/javascript; charset=utf-8');
|
||||
res.text.should.equal('typeof foo === \'function\' && foo({"str":"\\u2028 \\u2029 woot"});');
|
||||
done();
|
||||
});
|
||||
.expect('Content-Type', 'text/javascript; charset=utf-8')
|
||||
.expect(200, /foo\(\{"str":"\\u2028 \\u2029 woot"\}\);/, done);
|
||||
});
|
||||
|
||||
it('should not escape utf whitespace for json fallback', function(done){
|
||||
var app = express();
|
||||
|
||||
app.use(function(req, res){
|
||||
res.jsonp({ str: '\u2028 \u2029 woot' });
|
||||
});
|
||||
|
||||
request(app)
|
||||
.get('/')
|
||||
.expect('Content-Type', 'application/json; charset=utf-8')
|
||||
.expect(200, '{"str":"\u2028 \u2029 woot"}', done);
|
||||
});
|
||||
|
||||
it('should include security header and prologue', function (done) {
|
||||
var app = express();
|
||||
|
||||
app.use(function(req, res){
|
||||
res.jsonp({ count: 1 });
|
||||
});
|
||||
|
||||
request(app)
|
||||
.get('/?callback=something')
|
||||
.expect('Content-Type', 'text/javascript; charset=utf-8')
|
||||
.expect('X-Content-Type-Options', 'nosniff')
|
||||
.expect(200, /^\/\*\*\//, done);
|
||||
})
|
||||
|
||||
it('should not override previous Content-Types with no callback', function(done){
|
||||
var app = express();
|
||||
|
||||
@@ -127,7 +136,11 @@ describe('res', function(){
|
||||
request(app)
|
||||
.get('/')
|
||||
.expect('Content-Type', 'application/vnd.example+json; charset=utf-8')
|
||||
.expect(200, '{"hello":"world"}', done);
|
||||
.expect(200, '{"hello":"world"}', function (err, res) {
|
||||
if (err) return done(err);
|
||||
res.headers.should.not.have.property('x-content-type-options');
|
||||
done();
|
||||
});
|
||||
})
|
||||
|
||||
it('should override previous Content-Types with callback', function(done){
|
||||
@@ -141,6 +154,7 @@ describe('res', function(){
|
||||
request(app)
|
||||
.get('/?callback=cb')
|
||||
.expect('Content-Type', 'text/javascript; charset=utf-8')
|
||||
.expect('X-Content-Type-Options', 'nosniff')
|
||||
.expect(200, /cb\(\{"hello":"world"\}\);$/, done);
|
||||
})
|
||||
|
||||
|
||||
@@ -13,11 +13,8 @@ describe('res', function(){
|
||||
|
||||
request(app)
|
||||
.get('/')
|
||||
.end(function(err, res){
|
||||
res.statusCode.should.equal(302);
|
||||
res.headers.should.have.property('location', 'http://google.com');
|
||||
done();
|
||||
})
|
||||
.expect('location', 'http://google.com')
|
||||
.expect(302, done)
|
||||
})
|
||||
})
|
||||
|
||||
@@ -159,12 +156,11 @@ describe('res', function(){
|
||||
request(app)
|
||||
.get('/')
|
||||
.set('Accept', 'application/octet-stream')
|
||||
.end(function(err, res){
|
||||
res.should.have.status(302);
|
||||
res.headers.should.have.property('location', 'http://google.com');
|
||||
.expect('location', 'http://google.com')
|
||||
.expect('content-length', '0')
|
||||
.expect(302, '', function(err, res){
|
||||
if (err) return done(err)
|
||||
res.headers.should.not.have.property('content-type');
|
||||
res.headers.should.have.property('content-length', '0');
|
||||
res.text.should.equal('');
|
||||
done();
|
||||
})
|
||||
})
|
||||
|
||||
@@ -79,7 +79,7 @@ describe('res', function(){
|
||||
|
||||
request(app)
|
||||
.get('/')
|
||||
.expect(/user is not defined/, done);
|
||||
.expect(/Cannot read property 'name' of undefined/, done);
|
||||
})
|
||||
})
|
||||
|
||||
@@ -250,7 +250,7 @@ describe('res', function(){
|
||||
|
||||
request(app)
|
||||
.get('/')
|
||||
.expect(/is not defined/, done);
|
||||
.expect(/Cannot read property 'name' of undefined/, done);
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
171
test/res.send.js
171
test/res.send.js
@@ -77,6 +77,21 @@ describe('res', function(){
|
||||
})
|
||||
})
|
||||
|
||||
describe('.send(code, number)', function(){
|
||||
it('should send number as json', function(done){
|
||||
var app = express();
|
||||
|
||||
app.use(function(req, res){
|
||||
res.send(200, 0.123);
|
||||
});
|
||||
|
||||
request(app)
|
||||
.get('/')
|
||||
.expect('Content-Type', 'application/json; charset=utf-8')
|
||||
.expect(200, '0.123', done);
|
||||
})
|
||||
})
|
||||
|
||||
describe('.send(String)', function(){
|
||||
it('should send as html', function(done){
|
||||
var app = express();
|
||||
@@ -105,7 +120,7 @@ describe('res', function(){
|
||||
|
||||
request(app)
|
||||
.get('/')
|
||||
.expect('ETag', '"-1498647312"')
|
||||
.expect('ETag', 'W/"fz/jGo0ONwzb+aKy/rWipg=="')
|
||||
.end(done);
|
||||
})
|
||||
|
||||
@@ -194,7 +209,7 @@ describe('res', function(){
|
||||
|
||||
request(app)
|
||||
.get('/')
|
||||
.expect('ETag', '"-1498647312"')
|
||||
.expect('ETag', 'W/"fz/jGo0ONwzb+aKy/rWipg=="')
|
||||
.end(done);
|
||||
})
|
||||
|
||||
@@ -287,15 +302,16 @@ describe('res', function(){
|
||||
|
||||
it('should always check regardless of length', function(done){
|
||||
var app = express();
|
||||
var etag = '"asdf"';
|
||||
|
||||
app.use(function(req, res, next){
|
||||
res.set('ETag', 'asdf');
|
||||
res.set('ETag', etag);
|
||||
res.send('hey');
|
||||
});
|
||||
|
||||
request(app)
|
||||
.get('/')
|
||||
.set('If-None-Match', 'asdf')
|
||||
.set('If-None-Match', etag)
|
||||
.expect(304, done);
|
||||
})
|
||||
|
||||
@@ -309,22 +325,23 @@ describe('res', function(){
|
||||
|
||||
request(app)
|
||||
.get('/')
|
||||
.set('If-None-Match', '"-1498647312"')
|
||||
.set('If-None-Match', 'W/"fz/jGo0ONwzb+aKy/rWipg=="')
|
||||
.expect(304, done);
|
||||
})
|
||||
|
||||
it('should not perform freshness check unless 2xx or 304', function(done){
|
||||
var app = express();
|
||||
var etag = '"asdf"';
|
||||
|
||||
app.use(function(req, res, next){
|
||||
res.status(500);
|
||||
res.set('ETag', 'asdf');
|
||||
res.set('ETag', etag);
|
||||
res.send('hey');
|
||||
});
|
||||
|
||||
request(app)
|
||||
.get('/')
|
||||
.set('If-None-Match', 'asdf')
|
||||
.set('If-None-Match', etag)
|
||||
.expect('hey')
|
||||
.expect(500, done);
|
||||
})
|
||||
@@ -343,22 +360,35 @@ describe('res', function(){
|
||||
|
||||
describe('"etag" setting', function(){
|
||||
describe('when enabled', function(){
|
||||
it('should send ETag even when content-length < 1024', function(done){
|
||||
it('should send ETag', function(done){
|
||||
var app = express();
|
||||
|
||||
app.use(function(req, res){
|
||||
res.send('kajdslfkasdf');
|
||||
});
|
||||
|
||||
app.enable('etag');
|
||||
|
||||
request(app)
|
||||
.get('/')
|
||||
.end(function(err, res){
|
||||
res.headers.should.have.property('etag');
|
||||
done();
|
||||
});
|
||||
.expect('etag', 'W/"c-5aee35d8"', done)
|
||||
})
|
||||
|
||||
it('should send ETag ', function(done){
|
||||
it('should send ETag for empty string response', function(done){
|
||||
var app = express()
|
||||
|
||||
app.use(function(req, res){
|
||||
res.send('')
|
||||
});
|
||||
|
||||
app.enable('etag')
|
||||
|
||||
request(app)
|
||||
.get('/')
|
||||
.expect('etag', 'W/"0-0"', done)
|
||||
})
|
||||
|
||||
it('should send ETag for long response', function(done){
|
||||
var app = express();
|
||||
|
||||
app.use(function(req, res){
|
||||
@@ -366,13 +396,44 @@ describe('res', function(){
|
||||
res.send(str);
|
||||
});
|
||||
|
||||
app.enable('etag');
|
||||
|
||||
request(app)
|
||||
.get('/')
|
||||
.expect('etag', 'W/"fz/jGo0ONwzb+aKy/rWipg=="', done)
|
||||
});
|
||||
|
||||
it('should not override ETag when manually set', function(done){
|
||||
var app = express();
|
||||
|
||||
app.use(function(req, res){
|
||||
res.set('etag', '"asdf"');
|
||||
res.send(200);
|
||||
});
|
||||
|
||||
app.enable('etag');
|
||||
|
||||
request(app)
|
||||
.get('/')
|
||||
.expect('etag', '"asdf"', done)
|
||||
});
|
||||
|
||||
it('should not send ETag for res.send()', function(done){
|
||||
var app = express()
|
||||
|
||||
app.use(function(req, res){
|
||||
res.send()
|
||||
});
|
||||
|
||||
app.enable('etag')
|
||||
|
||||
request(app)
|
||||
.get('/')
|
||||
.end(function(err, res){
|
||||
res.headers.should.have.property('etag', '"-1498647312"');
|
||||
res.headers.should.not.have.property('etag');
|
||||
done();
|
||||
});
|
||||
});
|
||||
})
|
||||
})
|
||||
});
|
||||
|
||||
describe('when disabled', function(){
|
||||
@@ -400,17 +461,85 @@ describe('res', function(){
|
||||
app.disable('etag');
|
||||
|
||||
app.use(function(req, res){
|
||||
res.set('etag', 1);
|
||||
res.set('etag', '"asdf"');
|
||||
res.send(200);
|
||||
});
|
||||
|
||||
request(app)
|
||||
.get('/')
|
||||
.end(function(err, res){
|
||||
res.headers.should.have.property('etag');
|
||||
done();
|
||||
});
|
||||
.expect('etag', '"asdf"', done)
|
||||
});
|
||||
});
|
||||
|
||||
describe('when "strong"', function(){
|
||||
it('should send strong ETag', function(done){
|
||||
var app = express()
|
||||
|
||||
app.set('etag', 'strong');
|
||||
|
||||
app.use(function(req, res){
|
||||
res.send('hello, world!');
|
||||
});
|
||||
|
||||
request(app)
|
||||
.get('/')
|
||||
.expect('etag', '"Otu60XkfuuPskIiUxJY4cA=="', done)
|
||||
})
|
||||
})
|
||||
|
||||
describe('when "weak"', function(){
|
||||
it('should send weak ETag', function(done){
|
||||
var app = express()
|
||||
|
||||
app.set('etag', 'weak');
|
||||
|
||||
app.use(function(req, res){
|
||||
res.send('hello, world!');
|
||||
});
|
||||
|
||||
request(app)
|
||||
.get('/')
|
||||
.expect('etag', 'W/"d-58988d13"', done)
|
||||
})
|
||||
})
|
||||
|
||||
describe('when a function', function(){
|
||||
it('should send custom ETag', function(done){
|
||||
var app = express()
|
||||
|
||||
app.set('etag', function(body, encoding){
|
||||
body.should.equal('hello, world!')
|
||||
encoding.should.equal('utf8')
|
||||
return '"custom"'
|
||||
});
|
||||
|
||||
app.use(function(req, res){
|
||||
res.send('hello, world!');
|
||||
});
|
||||
|
||||
request(app)
|
||||
.get('/')
|
||||
.expect('etag', '"custom"', done)
|
||||
})
|
||||
|
||||
it('should not send falsy ETag', function(done){
|
||||
var app = express()
|
||||
|
||||
app.set('etag', function(body, encoding){
|
||||
return undefined
|
||||
});
|
||||
|
||||
app.use(function(req, res){
|
||||
res.send('hello, world!');
|
||||
});
|
||||
|
||||
request(app)
|
||||
.get('/')
|
||||
.end(function(err, res){
|
||||
res.headers.should.not.have.property('etag')
|
||||
done();
|
||||
})
|
||||
})
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
@@ -9,11 +9,7 @@ describe('res', function(){
|
||||
var app = express();
|
||||
|
||||
app.use(function(req, res){
|
||||
res.sendfile('test/fixtures/user.html', function(err){
|
||||
assert(!err);
|
||||
req.socket.listeners('error').should.have.length(1); // node's original handler
|
||||
done();
|
||||
});
|
||||
res.sendfile('test/fixtures/user.html', done)
|
||||
});
|
||||
|
||||
request(app)
|
||||
@@ -110,6 +106,54 @@ describe('res', function(){
|
||||
})
|
||||
|
||||
describe('.sendfile(path)', function(){
|
||||
it('should not serve dotfiles', function(done){
|
||||
var app = express();
|
||||
|
||||
app.use(function(req, res){
|
||||
res.sendfile('test/fixtures/.name');
|
||||
});
|
||||
|
||||
request(app)
|
||||
.get('/')
|
||||
.expect(404, done);
|
||||
})
|
||||
|
||||
it('should accept dotfiles option', function(done){
|
||||
var app = express();
|
||||
|
||||
app.use(function(req, res){
|
||||
res.sendfile('test/fixtures/.name', { dotfiles: 'allow' });
|
||||
});
|
||||
|
||||
request(app)
|
||||
.get('/')
|
||||
.expect(200, 'tobi', done);
|
||||
})
|
||||
|
||||
it('should transfer a file', function (done) {
|
||||
var app = express();
|
||||
|
||||
app.use(function (req, res) {
|
||||
res.sendfile('test/fixtures/name.txt');
|
||||
});
|
||||
|
||||
request(app)
|
||||
.get('/')
|
||||
.expect(200, 'tobi', done);
|
||||
});
|
||||
|
||||
it('should transfer a directory index file', function (done) {
|
||||
var app = express();
|
||||
|
||||
app.use(function (req, res) {
|
||||
res.sendfile('test/fixtures/blog/');
|
||||
});
|
||||
|
||||
request(app)
|
||||
.get('/')
|
||||
.expect(200, '<b>index</b>', done);
|
||||
});
|
||||
|
||||
describe('with an absolute path', function(){
|
||||
it('should transfer the file', function(done){
|
||||
var app = express();
|
||||
|
||||
@@ -20,8 +20,8 @@ describe('res', function(){
|
||||
|
||||
it('should coerce to a string', function(){
|
||||
res.headers = {};
|
||||
res.set('ETag', 123);
|
||||
res.get('ETag').should.equal('123');
|
||||
res.set('X-Number', 123);
|
||||
res.get('X-Number').should.equal('123');
|
||||
})
|
||||
})
|
||||
|
||||
@@ -41,8 +41,9 @@ describe('res', function(){
|
||||
|
||||
it('should coerce to an array of strings', function(){
|
||||
res.headers = {};
|
||||
res.set('ETag', [123, 456]);
|
||||
JSON.stringify(res.get('ETag')).should.equal('["123","456"]');
|
||||
res.set('X-Numbers', [123, 456]);
|
||||
JSON.stringify(res.get('X-Numbers'))
|
||||
.should.equal('["123","456"]');
|
||||
})
|
||||
})
|
||||
|
||||
@@ -66,8 +67,8 @@ describe('res', function(){
|
||||
|
||||
it('should coerce to a string', function(){
|
||||
res.headers = {};
|
||||
res.set({ ETag: 123 });
|
||||
res.get('ETag').should.equal('123');
|
||||
res.set({ 'X-Number': 123 });
|
||||
res.get('X-Number').should.equal('123');
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
@@ -1,2 +1,3 @@
|
||||
|
||||
process.env.NODE_ENV = 'test';
|
||||
process.env.NO_DEPRECATION = 'connect,express';
|
||||
|
||||
@@ -2,24 +2,50 @@
|
||||
var utils = require('../lib/utils')
|
||||
, assert = require('assert');
|
||||
|
||||
describe('utils.etag(body)', function(){
|
||||
|
||||
var str = 'Hello CRC';
|
||||
var strUTF8 = '<!DOCTYPE html>\n<html>\n<head>\n</head>\n<body><p>自動販売</p></body></html>';
|
||||
|
||||
describe('utils.etag(body, encoding)', function(){
|
||||
it('should support strings', function(){
|
||||
utils.etag(str).should.eql('"-2034458343"');
|
||||
utils.etag('express!')
|
||||
.should.eql('"zZdv4imtWD49AHEviejT6A=="')
|
||||
})
|
||||
|
||||
it('should support utf8 strings', function(){
|
||||
utils.etag(strUTF8).should.eql('"1395090196"');
|
||||
utils.etag('express❤', 'utf8')
|
||||
.should.eql('"fsFba4IxwQS6h6Umb+FNxw=="')
|
||||
})
|
||||
|
||||
it('should support buffer', function(){
|
||||
utils.etag(new Buffer(strUTF8)).should.eql('"1395090196"');
|
||||
utils.etag(new Buffer(str)).should.eql('"-2034458343"');
|
||||
var buf = new Buffer('express!')
|
||||
utils.etag(buf)
|
||||
.should.eql('"zZdv4imtWD49AHEviejT6A=="');
|
||||
})
|
||||
|
||||
it('should support empty string', function(){
|
||||
utils.etag('')
|
||||
.should.eql('"1B2M2Y8AsgTpgAmY7PhCfg=="');
|
||||
})
|
||||
})
|
||||
|
||||
describe('utils.wetag(body, encoding)', function(){
|
||||
it('should support strings', function(){
|
||||
utils.wetag('express!')
|
||||
.should.eql('W/"8-b8aabac7"')
|
||||
})
|
||||
|
||||
it('should support utf8 strings', function(){
|
||||
utils.wetag('express❤', 'utf8')
|
||||
.should.eql('W/"a-686b0af1"')
|
||||
})
|
||||
|
||||
it('should support buffer', function(){
|
||||
var buf = new Buffer('express!')
|
||||
utils.wetag(buf)
|
||||
.should.eql('W/"8-b8aabac7"');
|
||||
})
|
||||
|
||||
it('should support empty string', function(){
|
||||
utils.wetag('')
|
||||
.should.eql('W/"0-0"');
|
||||
})
|
||||
})
|
||||
|
||||
describe('utils.isAbsolute()', function(){
|
||||
@@ -28,7 +54,11 @@ describe('utils.isAbsolute()', function(){
|
||||
assert(!utils.isAbsolute(':\\'));
|
||||
})
|
||||
|
||||
it('should unices', function(){
|
||||
it('should support windows unc', function(){
|
||||
assert(utils.isAbsolute('\\\\foo\\bar'))
|
||||
})
|
||||
|
||||
it('should support unices', function(){
|
||||
assert(utils.isAbsolute('/foo/bar'));
|
||||
assert(!utils.isAbsolute('foo/bar'));
|
||||
})
|
||||
@@ -42,13 +72,6 @@ describe('utils.flatten(arr)', function(){
|
||||
})
|
||||
})
|
||||
|
||||
describe('utils.escape(html)', function(){
|
||||
it('should escape html entities', function(){
|
||||
utils.escape('<script>foo & "bar"')
|
||||
.should.equal('<script>foo & "bar"')
|
||||
})
|
||||
})
|
||||
|
||||
describe('utils.parseParams(str)', function(){
|
||||
it('should default quality to 1', function(){
|
||||
utils.parseParams('text/html')
|
||||
@@ -218,4 +241,10 @@ describe('utils.accepts(type, str)', function(){
|
||||
.should.equal('html');
|
||||
})
|
||||
})
|
||||
|
||||
describe('when params included', function(){
|
||||
it('should match params', function(){
|
||||
assert(null == utils.accepts('text/html; charset=us-ascii', 'text/html; charset=utf-8'));
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
Reference in New Issue
Block a user