mirror of
https://github.com/expressjs/express.git
synced 2026-02-26 18:57:43 +00:00
Compare commits
401 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
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 | ||
|
|
f6bbeafd26 | ||
|
|
f14e39d451 | ||
|
|
084f5d891b | ||
|
|
b0f72e13d9 | ||
|
|
8d7d80ef9d | ||
|
|
cf5de082b5 | ||
|
|
1944451082 | ||
|
|
602e5a8200 | ||
|
|
83b8b7acb7 | ||
|
|
e660f19507 | ||
|
|
ff412b927d | ||
|
|
392ef1eb06 | ||
|
|
dcecdc9be6 | ||
|
|
ed69b68892 | ||
|
|
42b982e13c | ||
|
|
359f12791a | ||
|
|
b91cd66fc5 | ||
|
|
787d630157 | ||
|
|
1f938c560a | ||
|
|
a96924a555 | ||
|
|
33dc6629ff | ||
|
|
1b3fb0af8c | ||
|
|
12da523ff7 | ||
|
|
0f49d80623 | ||
|
|
1717516a78 | ||
|
|
328c6d3060 | ||
|
|
566720be15 | ||
|
|
65f13c3cc6 | ||
|
|
d98e2e7498 | ||
|
|
f7be983a77 | ||
|
|
a2553126dd | ||
|
|
0639c45acd | ||
|
|
920f46ad65 | ||
|
|
35a66d8a14 | ||
|
|
4e1e252e17 | ||
|
|
0461e55380 | ||
|
|
8dc4ff26f9 | ||
|
|
6f9e927633 | ||
|
|
40a43eb753 | ||
|
|
a8bb4bab2b | ||
|
|
417999884b | ||
|
|
17a739e35f | ||
|
|
66b38b58bc | ||
|
|
dc31ea34b8 | ||
|
|
d58ca520c8 | ||
|
|
4b646c2f8d | ||
|
|
35757ed1f5 | ||
|
|
fed0d5df5c | ||
|
|
c99fa6a192 | ||
|
|
0d468cbe6c | ||
|
|
f92ba6d0cf | ||
|
|
0408e3727e | ||
|
|
d5815922ca | ||
|
|
972c01afc9 | ||
|
|
8894e30869 | ||
|
|
5d8dba5fe0 | ||
|
|
90fbc1a33e | ||
|
|
55dea47b94 | ||
|
|
c7791a207b | ||
|
|
30d18888b9 | ||
|
|
df50669092 | ||
|
|
abd6b7c5c3 | ||
|
|
87912103c9 | ||
|
|
4ce1ee458e | ||
|
|
8aff64f89a | ||
|
|
ff23423d34 | ||
|
|
1d97599f8b | ||
|
|
e465624fd0 | ||
|
|
dc5932d177 | ||
|
|
cfd93b7529 | ||
|
|
8b2208f394 | ||
|
|
00a3b01f39 | ||
|
|
3baca251f0 | ||
|
|
72daae1d92 | ||
|
|
fcbe53ddb5 | ||
|
|
e9851672eb | ||
|
|
9a45f7bd3d | ||
|
|
85834fd146 | ||
|
|
a0c1ac7b45 | ||
|
|
7b0dca0f9c | ||
|
|
34c83d7d29 | ||
|
|
7c6882234e | ||
|
|
2e68ddbae9 | ||
|
|
7724fc6af7 | ||
|
|
2939075f03 | ||
|
|
606f68de02 | ||
|
|
863160ae49 | ||
|
|
edd39fb194 | ||
|
|
a71d264d45 | ||
|
|
8a7a695836 | ||
|
|
de54af4061 | ||
|
|
2f2a652bc9 | ||
|
|
1e638663de | ||
|
|
1684a8792a | ||
|
|
f47c0d9774 | ||
|
|
89e7264e53 | ||
|
|
cada9f61c8 | ||
|
|
373fa55981 | ||
|
|
2bc703cfc2 | ||
|
|
c9865b821d | ||
|
|
9c0de23645 | ||
|
|
b7a38af41d | ||
|
|
661914781e | ||
|
|
6e3f3887e9 | ||
|
|
a66d6bb034 | ||
|
|
2e197e2b98 | ||
|
|
55d1a4f964 | ||
|
|
82a7d7a977 | ||
|
|
dae54b456f | ||
|
|
1b7a044f33 | ||
|
|
18264403b1 | ||
|
|
04d43b7039 | ||
|
|
2dfecfb661 | ||
|
|
250f1f5f6e | ||
|
|
3ac718763f | ||
|
|
05e1555c0d | ||
|
|
855d1e2bf5 | ||
|
|
f0bfb3b2b2 | ||
|
|
4b4db0f7fb | ||
|
|
9bed2b80ee | ||
|
|
bb157c0cbf | ||
|
|
1ef05d4a28 | ||
|
|
0b88208022 | ||
|
|
c9d9ed3493 | ||
|
|
bd8b9f5781 | ||
|
|
9cbcf23df0 | ||
|
|
36e42db05b | ||
|
|
2bf6a1d813 | ||
|
|
e8373d3564 | ||
|
|
e218377a3d | ||
|
|
7d1aed4955 | ||
|
|
b4acbcf1fe | ||
|
|
50cb62c5d2 | ||
|
|
4cf868bd74 | ||
|
|
baa5a7c3e9 | ||
|
|
ee228f7aea | ||
|
|
d5b11c7d1b | ||
|
|
ed7db34bab | ||
|
|
57e45e3af8 | ||
|
|
1dc46478cb | ||
|
|
113ed0927d | ||
|
|
ab8be2d741 | ||
|
|
3b53b11fcd | ||
|
|
9fb661559b | ||
|
|
04882cf72c | ||
|
|
288176bbc9 | ||
|
|
5638a4fc62 | ||
|
|
3b4ce91fa3 | ||
|
|
1c87e5e9a8 | ||
|
|
a887e6a881 | ||
|
|
69290cad6f | ||
|
|
b66c7da05f | ||
|
|
92ddf77453 | ||
|
|
8e2f538983 | ||
|
|
2817d8caf2 | ||
|
|
b7f08fb159 | ||
|
|
0c2768f5bd | ||
|
|
09bede1a92 | ||
|
|
7059d3b71e | ||
|
|
e5de08faa1 | ||
|
|
e43ff076fd | ||
|
|
3ea7381dea | ||
|
|
f1c46f51e5 | ||
|
|
297fb4e0b0 | ||
|
|
9e406dfee2 | ||
|
|
30b7aa8a17 | ||
|
|
c1d16e0016 | ||
|
|
929ffb8d77 | ||
|
|
197a2e3b54 | ||
|
|
6cf6c8b918 | ||
|
|
058d7ec2ea | ||
|
|
752b5f705e | ||
|
|
e7fa579637 | ||
|
|
97781d4112 | ||
|
|
3ddd8e66a7 | ||
|
|
8a1e865e37 | ||
|
|
e850cb3ea3 | ||
|
|
13d3efe8df | ||
|
|
d6ecf785a2 | ||
|
|
19cb39869f | ||
|
|
a38bdf6758 | ||
|
|
bdbdab7fcc | ||
|
|
5aa9670120 | ||
|
|
8ad8cb93cc | ||
|
|
610e172fcf | ||
|
|
6942070a21 | ||
|
|
e283200511 | ||
|
|
54a192a5c5 | ||
|
|
c3bd65eda2 | ||
|
|
7c2ed1d2d6 | ||
|
|
3de81e0147 | ||
|
|
8fe1e2a5b4 | ||
|
|
909dbb81d5 | ||
|
|
26802a689c | ||
|
|
37239fb67f | ||
|
|
018dc40b32 | ||
|
|
52440955e6 | ||
|
|
c2f3d6ce2b | ||
|
|
be858f5d07 | ||
|
|
1f14734f91 | ||
|
|
6d1d694dbb | ||
|
|
ba5c48aa86 | ||
|
|
320d7807a9 | ||
|
|
6650a312b7 | ||
|
|
832c3b3744 | ||
|
|
76691bfd6b | ||
|
|
29fe5ea785 | ||
|
|
7a31a1d311 | ||
|
|
52a820113f | ||
|
|
aec3428489 | ||
|
|
a10f695b6f | ||
|
|
a3c9eacaf1 | ||
|
|
19d685b152 | ||
|
|
8ab44081d4 | ||
|
|
0431d22822 | ||
|
|
138d74aefa | ||
|
|
28562b2cf8 | ||
|
|
e0afda444f | ||
|
|
5a4cac58af | ||
|
|
545dca6c4d | ||
|
|
e59a882389 | ||
|
|
ccd9828535 | ||
|
|
41f0d32355 | ||
|
|
2f19b4fefc | ||
|
|
cd31cecfd1 | ||
|
|
2fe46b3905 | ||
|
|
24974f1f8f | ||
|
|
fd73bd006e | ||
|
|
7388c2c223 | ||
|
|
e2210b0b92 | ||
|
|
30919be2a0 | ||
|
|
10b21b41f7 | ||
|
|
28b8a3b5f7 | ||
|
|
8b2f1bba95 | ||
|
|
c805d80a9b | ||
|
|
d876778d22 | ||
|
|
412e571600 | ||
|
|
3296ed9cb3 | ||
|
|
91835e6816 | ||
|
|
28752cc3c0 | ||
|
|
5fa685b602 | ||
|
|
eb1bbb92c0 |
5
.gitignore
vendored
5
.gitignore
vendored
@@ -1,6 +1,5 @@
|
||||
coverage.html
|
||||
coverage/
|
||||
.DS_Store
|
||||
lib-cov
|
||||
*.seed
|
||||
*.log
|
||||
*.csv
|
||||
@@ -13,7 +12,5 @@ benchmarks/graphs
|
||||
testing
|
||||
node_modules/
|
||||
testing
|
||||
.coverage_data
|
||||
cover_html
|
||||
test.js
|
||||
.idea
|
||||
|
||||
0
.gitmodules
vendored
0
.gitmodules
vendored
@@ -1,9 +1,10 @@
|
||||
.git*
|
||||
benchmarks/
|
||||
coverage/
|
||||
docs/
|
||||
examples/
|
||||
support/
|
||||
test/
|
||||
testing.js
|
||||
.DS_Store
|
||||
coverage.html
|
||||
lib-cov
|
||||
.travis.yml
|
||||
|
||||
@@ -2,3 +2,10 @@ language: node_js
|
||||
node_js:
|
||||
- "0.8"
|
||||
- "0.10"
|
||||
- "0.11"
|
||||
matrix:
|
||||
allow_failures:
|
||||
- node_js: "0.11"
|
||||
fast_finish: true
|
||||
script: "npm run-script test-travis"
|
||||
after_script: "npm install coveralls@2.10.0 && cat ./coverage/lcov.info | coveralls"
|
||||
|
||||
687
History.md
687
History.md
@@ -1,21 +1,686 @@
|
||||
3.17.6 / 2014-10-02
|
||||
===================
|
||||
|
||||
3.2.4 / 2013-05-09
|
||||
* 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
|
||||
==================
|
||||
|
||||
* keep previous `Content-Type` for `res.jsonp`
|
||||
* set proper `charset` in `Content-Type` for `res.send`
|
||||
* update connect to 2.17.1
|
||||
- fix `res.charset` appending charset when `content-type` has one
|
||||
- deps: express-session@1.2.0
|
||||
- deps: morgan@1.1.1
|
||||
- deps: serve-index@1.0.3
|
||||
|
||||
3.7.0 / 2014-05-18
|
||||
==================
|
||||
|
||||
* proper proxy trust with `app.set('trust proxy', trust)`
|
||||
- `app.set('trust proxy', 1)` trust first hop
|
||||
- `app.set('trust proxy', 'loopback')` trust loopback addresses
|
||||
- `app.set('trust proxy', '10.0.0.1')` trust single IP
|
||||
- `app.set('trust proxy', '10.0.0.1/16')` trust subnet
|
||||
- `app.set('trust proxy', '10.0.0.1, 10.0.0.2')` trust list
|
||||
- `app.set('trust proxy', false)` turn off
|
||||
- `app.set('trust proxy', true)` trust everything
|
||||
* update connect to 2.16.2
|
||||
- deprecate `res.headerSent` -- use `res.headersSent`
|
||||
- deprecate `res.on("header")` -- use on-headers module instead
|
||||
- fix edge-case in `res.appendHeader` that would append in wrong order
|
||||
- json: use body-parser
|
||||
- urlencoded: use body-parser
|
||||
- dep: bytes@1.0.0
|
||||
- dep: cookie-parser@1.1.0
|
||||
- dep: csurf@1.2.0
|
||||
- dep: express-session@1.1.0
|
||||
- dep: method-override@1.0.1
|
||||
|
||||
3.6.0 / 2014-05-09
|
||||
==================
|
||||
|
||||
* deprecate `app.del()` -- use `app.delete()` instead
|
||||
* deprecate `res.json(obj, status)` -- use `res.json(status, obj)` instead
|
||||
- the edge-case `res.json(status, num)` requires `res.status(status).json(num)`
|
||||
* deprecate `res.jsonp(obj, status)` -- use `res.jsonp(status, obj)` instead
|
||||
- the edge-case `res.jsonp(status, num)` requires `res.status(status).jsonp(num)`
|
||||
* support PURGE method
|
||||
- add `app.purge`
|
||||
- add `router.purge`
|
||||
- include PURGE in `app.all`
|
||||
* update connect to 2.15.0
|
||||
* Add `res.appendHeader`
|
||||
* Call error stack even when response has been sent
|
||||
* Patch `res.headerSent` to return Boolean
|
||||
* Patch `res.headersSent` for node.js 0.8
|
||||
* Prevent default 404 handler after response sent
|
||||
* dep: compression@1.0.2
|
||||
* dep: connect-timeout@1.1.0
|
||||
* dep: debug@^0.8.0
|
||||
* dep: errorhandler@1.0.1
|
||||
* dep: express-session@1.0.4
|
||||
* dep: morgan@1.0.1
|
||||
* dep: serve-favicon@2.0.0
|
||||
* dep: serve-index@1.0.2
|
||||
* update debug to 0.8.0
|
||||
* add `enable()` method
|
||||
* change from stderr to stdout
|
||||
* update methods to 1.0.0
|
||||
- add PURGE
|
||||
* update mkdirp to 0.5.0
|
||||
|
||||
3.5.3 / 2014-05-08
|
||||
==================
|
||||
|
||||
* fix `req.host` for IPv6 literals
|
||||
* fix `res.jsonp` error if callback param is object
|
||||
|
||||
3.5.2 / 2014-04-24
|
||||
==================
|
||||
|
||||
* update connect to 2.14.5
|
||||
* update cookie to 0.1.2
|
||||
* update mkdirp to 0.4.0
|
||||
* update send to 0.3.0
|
||||
|
||||
3.5.1 / 2014-03-25
|
||||
==================
|
||||
|
||||
* pin less-middleware in generated app
|
||||
|
||||
3.5.0 / 2014-03-06
|
||||
==================
|
||||
|
||||
* bump deps
|
||||
|
||||
3.4.8 / 2014-01-13
|
||||
==================
|
||||
|
||||
* prevent incorrect automatic OPTIONS responses #1868 @dpatti
|
||||
* update binary and examples for jade 1.0 #1876 @yossi, #1877 @reqshark, #1892 @matheusazzi
|
||||
* throw 400 in case of malformed paths @rlidwka
|
||||
|
||||
3.4.7 / 2013-12-10
|
||||
==================
|
||||
|
||||
* update connect
|
||||
|
||||
3.4.6 / 2013-12-01
|
||||
==================
|
||||
|
||||
* update connect (raw-body)
|
||||
|
||||
3.4.5 / 2013-11-27
|
||||
==================
|
||||
|
||||
* update connect
|
||||
* res.location: remove leading ./ #1802 @kapouer
|
||||
* res.redirect: fix `res.redirect('toString') #1829 @michaelficarra
|
||||
* res.send: always send ETag when content-length > 0
|
||||
* router: add Router.all() method
|
||||
|
||||
3.4.4 / 2013-10-29
|
||||
==================
|
||||
|
||||
* update connect
|
||||
* update supertest
|
||||
* update methods
|
||||
* express(1): replace bodyParser() with urlencoded() and json() #1795 @chirag04
|
||||
|
||||
3.4.3 / 2013-10-23
|
||||
==================
|
||||
|
||||
* update connect
|
||||
|
||||
3.4.2 / 2013-10-18
|
||||
==================
|
||||
|
||||
* update connect
|
||||
* downgrade commander
|
||||
|
||||
3.4.1 / 2013-10-15
|
||||
==================
|
||||
|
||||
* update connect
|
||||
* update commander
|
||||
* jsonp: check if callback is a function
|
||||
* router: wrap encodeURIComponent in a try/catch #1735 (@lxe)
|
||||
* res.format: now includes chraset @1747 (@sorribas)
|
||||
* res.links: allow multiple calls @1746 (@sorribas)
|
||||
|
||||
3.4.0 / 2013-09-07
|
||||
==================
|
||||
|
||||
* add res.vary(). Closes #1682
|
||||
* update connect
|
||||
|
||||
3.3.8 / 2013-09-02
|
||||
==================
|
||||
|
||||
* update connect
|
||||
|
||||
3.3.7 / 2013-08-28
|
||||
==================
|
||||
|
||||
* update connect
|
||||
|
||||
3.3.6 / 2013-08-27
|
||||
==================
|
||||
|
||||
* Revert "remove charset from json responses. Closes #1631" (causes issues in some clients)
|
||||
* add: req.accepts take an argument list
|
||||
|
||||
3.3.4 / 2013-07-08
|
||||
==================
|
||||
|
||||
* update send and connect
|
||||
|
||||
3.3.3 / 2013-07-04
|
||||
==================
|
||||
|
||||
* update connect
|
||||
|
||||
3.3.2 / 2013-07-03
|
||||
==================
|
||||
|
||||
* update connect
|
||||
* update send
|
||||
* remove .version export
|
||||
|
||||
3.3.1 / 2013-06-27
|
||||
==================
|
||||
|
||||
* update connect
|
||||
|
||||
3.3.0 / 2013-06-26
|
||||
==================
|
||||
|
||||
* update connect
|
||||
* add support for multiple X-Forwarded-Proto values. Closes #1646
|
||||
* change: remove charset from json responses. Closes #1631
|
||||
* change: return actual booleans from req.accept* functions
|
||||
* fix jsonp callback array throw
|
||||
|
||||
3.2.6 / 2013-06-02
|
||||
==================
|
||||
|
||||
* update connect
|
||||
|
||||
3.2.5 / 2013-05-21
|
||||
==================
|
||||
|
||||
* update connect
|
||||
* update node-cookie
|
||||
* add: throw a meaningful error when there is no default engine
|
||||
* change generation of ETags with res.send() to GET requests only. Closes #1619
|
||||
|
||||
3.2.4 / 2013-05-09
|
||||
==================
|
||||
|
||||
* fix `req.subdomains` when no Host is present
|
||||
* fix `req.host` when no Host is present, return undefined
|
||||
|
||||
3.2.3 / 2013-05-07
|
||||
3.2.3 / 2013-05-07
|
||||
==================
|
||||
|
||||
* update connect / qs
|
||||
|
||||
3.2.2 / 2013-05-03
|
||||
3.2.2 / 2013-05-03
|
||||
==================
|
||||
|
||||
* update qs
|
||||
|
||||
3.2.1 / 2013-04-29
|
||||
3.2.1 / 2013-04-29
|
||||
==================
|
||||
|
||||
* add app.VERB() paths array deprecation warning
|
||||
@@ -23,27 +688,27 @@
|
||||
* update qs and remove all ~ semver crap
|
||||
* fix: accept number as value of Signed Cookie
|
||||
|
||||
3.2.0 / 2013-04-15
|
||||
3.2.0 / 2013-04-15
|
||||
==================
|
||||
|
||||
* add "view" constructor setting to override view behaviour
|
||||
* add req.acceptsEncoding(name)
|
||||
* add req.acceptedEncodings
|
||||
* revert cookie signature change causing session race conditions
|
||||
* fix sorting of Accept values of the same quality
|
||||
* fix sorting of Accept values of the same quality
|
||||
|
||||
3.1.2 / 2013-04-12
|
||||
3.1.2 / 2013-04-12
|
||||
==================
|
||||
|
||||
* add support for custom Accept parameters
|
||||
* update cookie-signature
|
||||
|
||||
3.1.1 / 2013-04-01
|
||||
3.1.1 / 2013-04-01
|
||||
==================
|
||||
|
||||
* add X-Forwarded-Host support to `req.host`
|
||||
* fix relative redirects
|
||||
* update mkdirp
|
||||
* fix relative redirects
|
||||
* update mkdirp
|
||||
* update buffer-crc32
|
||||
* remove legacy app.configure() method from app template.
|
||||
|
||||
|
||||
2
LICENSE
2
LICENSE
@@ -1,6 +1,6 @@
|
||||
(The MIT License)
|
||||
|
||||
Copyright (c) 2009-2011 TJ Holowaychuk <tj@vision-media.ca>
|
||||
Copyright (c) 2009-2013 TJ Holowaychuk <tj@vision-media.ca>
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining
|
||||
a copy of this software and associated documentation files (the
|
||||
|
||||
33
Makefile
33
Makefile
@@ -1,33 +0,0 @@
|
||||
|
||||
MOCHA_OPTS= --check-leaks
|
||||
REPORTER = dot
|
||||
|
||||
check: test
|
||||
|
||||
test: test-unit test-acceptance
|
||||
|
||||
test-unit:
|
||||
@NODE_ENV=test ./node_modules/.bin/mocha \
|
||||
--reporter $(REPORTER) \
|
||||
$(MOCHA_OPTS)
|
||||
|
||||
test-acceptance:
|
||||
@NODE_ENV=test ./node_modules/.bin/mocha \
|
||||
--reporter $(REPORTER) \
|
||||
--bail \
|
||||
test/acceptance/*.js
|
||||
|
||||
test-cov: lib-cov
|
||||
@EXPRESS_COV=1 $(MAKE) test REPORTER=html-cov > coverage.html
|
||||
|
||||
lib-cov:
|
||||
@jscoverage lib lib-cov
|
||||
|
||||
benchmark:
|
||||
@./support/bench
|
||||
|
||||
clean:
|
||||
rm -f coverage.html
|
||||
rm -fr lib-cov
|
||||
|
||||
.PHONY: test test-unit test-acceptance benchmark clean
|
||||
99
Readme.md
99
Readme.md
@@ -1,6 +1,11 @@
|
||||

|
||||
[](http://expressjs.com/)
|
||||
|
||||
Fast, unopinionated, minimalist web framework for [node](http://nodejs.org). [](http://travis-ci.org/visionmedia/express) [](https://gemnasium.com/visionmedia/express)
|
||||
Fast, unopinionated, minimalist web framework for [node](http://nodejs.org).
|
||||
|
||||
[](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');
|
||||
@@ -48,111 +53,57 @@ app.listen(3000);
|
||||
|
||||
## Philosophy
|
||||
|
||||
The Express philosophy is to provide small, robust tooling for HTTP servers. Making
|
||||
The Express philosophy is to provide small, robust tooling for HTTP servers, making
|
||||
it a great solution for single page applications, web sites, hybrids, or public
|
||||
HTTP APIs.
|
||||
|
||||
Built on Connect you can use _only_ what you need, and nothing more, applications
|
||||
Built on Connect, you can use _only_ what you need, and nothing more. Applications
|
||||
can be as big or as small as you like, even a single file. Express does
|
||||
not force you to use any specific ORM or template engine. With support for over
|
||||
14 template engines via [Consolidate.js](http://github.com/visionmedia/consolidate.js)
|
||||
14 template engines via [Consolidate.js](http://github.com/visionmedia/consolidate.js),
|
||||
you can quickly craft your perfect framework.
|
||||
|
||||
## More Information
|
||||
|
||||
* [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)
|
||||
* [日本語ドキュメンテーション](http://hideyukisaito.com/doc/expressjs/) by [hideyukisaito](https://github.com/hideyukisaito)
|
||||
* Visit the [Wiki](http://github.com/strongloop/express/wiki)
|
||||
* [Русскоязычная документация](http://jsman.ru/express/)
|
||||
* Run express examples [online](https://runnable.com/express)
|
||||
|
||||
## Viewing Examples
|
||||
|
||||
Clone the Express repo, then install the dev dependencies to install all the example / test suite deps:
|
||||
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
|
||||
|
||||
then run whichever tests you want:
|
||||
Then run whichever tests you want:
|
||||
|
||||
$ node examples/content-negotiation
|
||||
|
||||
You can also view live examples here:
|
||||
|
||||
<a href="https://runnable.com/express" target="_blank"><img src="https://runnable.com/external/styles/assets/runnablebtn.png" style="width:67px;height:25px;"></a>
|
||||
|
||||
## Running Tests
|
||||
|
||||
To run the test suite first invoke the following command within the repo, installing the development dependencies:
|
||||
To run the test suite, first invoke the following command within the repo, installing the development dependencies:
|
||||
|
||||
$ npm install
|
||||
|
||||
then run the tests:
|
||||
Then run the tests:
|
||||
|
||||
$ make test
|
||||
```sh
|
||||
$ npm test
|
||||
```
|
||||
|
||||
## Contributors
|
||||
|
||||
```
|
||||
project: express
|
||||
commits: 3559
|
||||
active : 468 days
|
||||
files : 237
|
||||
authors:
|
||||
1891 Tj Holowaychuk 53.1%
|
||||
1285 visionmedia 36.1%
|
||||
182 TJ Holowaychuk 5.1%
|
||||
54 Aaron Heckmann 1.5%
|
||||
34 csausdev 1.0%
|
||||
26 ciaranj 0.7%
|
||||
21 Robert Sköld 0.6%
|
||||
6 Guillermo Rauch 0.2%
|
||||
3 Dav Glass 0.1%
|
||||
3 Nick Poulden 0.1%
|
||||
2 Randy Merrill 0.1%
|
||||
2 Benny Wong 0.1%
|
||||
2 Hunter Loftis 0.1%
|
||||
2 Jake Gordon 0.1%
|
||||
2 Brian McKinney 0.1%
|
||||
2 Roman Shtylman 0.1%
|
||||
2 Ben Weaver 0.1%
|
||||
2 Dave Hoover 0.1%
|
||||
2 Eivind Fjeldstad 0.1%
|
||||
2 Daniel Shaw 0.1%
|
||||
1 Matt Colyer 0.0%
|
||||
1 Pau Ramon 0.0%
|
||||
1 Pero Pejovic 0.0%
|
||||
1 Peter Rekdal Sunde 0.0%
|
||||
1 Raynos 0.0%
|
||||
1 Teng Siong Ong 0.0%
|
||||
1 Viktor Kelemen 0.0%
|
||||
1 ctide 0.0%
|
||||
1 8bitDesigner 0.0%
|
||||
1 isaacs 0.0%
|
||||
1 mgutz 0.0%
|
||||
1 pikeas 0.0%
|
||||
1 shuwatto 0.0%
|
||||
1 tstrimple 0.0%
|
||||
1 ewoudj 0.0%
|
||||
1 Adam Sanderson 0.0%
|
||||
1 Andrii Kostenko 0.0%
|
||||
1 Andy Hiew 0.0%
|
||||
1 Arpad Borsos 0.0%
|
||||
1 Ashwin Purohit 0.0%
|
||||
1 Benjen 0.0%
|
||||
1 Darren Torpey 0.0%
|
||||
1 Greg Ritter 0.0%
|
||||
1 Gregory Ritter 0.0%
|
||||
1 James Herdman 0.0%
|
||||
1 Jim Snodgrass 0.0%
|
||||
1 Joe McCann 0.0%
|
||||
1 Jonathan Dumaine 0.0%
|
||||
1 Jonathan Palardy 0.0%
|
||||
1 Jonathan Zacsh 0.0%
|
||||
1 Justin Lilly 0.0%
|
||||
1 Ken Sato 0.0%
|
||||
1 Maciej Małecki 0.0%
|
||||
1 Masahiro Hayashi 0.0%
|
||||
```
|
||||
https://github.com/strongloop/express/graphs/contributors
|
||||
|
||||
## License
|
||||
|
||||
|
||||
13
benchmarks/Makefile
Normal file
13
benchmarks/Makefile
Normal file
@@ -0,0 +1,13 @@
|
||||
|
||||
all:
|
||||
@./run 1 middleware
|
||||
@./run 5 middleware
|
||||
@./run 10 middleware
|
||||
@./run 15 middleware
|
||||
@./run 20 middleware
|
||||
@./run 30 middleware
|
||||
@./run 50 middleware
|
||||
@./run 100 middleware
|
||||
@echo
|
||||
|
||||
.PHONY: all
|
||||
23
benchmarks/middleware.js
Normal file
23
benchmarks/middleware.js
Normal file
@@ -0,0 +1,23 @@
|
||||
|
||||
var http = require('http');
|
||||
var express = require('..');
|
||||
var app = express();
|
||||
|
||||
// number of middleware
|
||||
|
||||
var n = parseInt(process.env.MW || '1', 10);
|
||||
console.log(' %s middleware', n);
|
||||
|
||||
while (n--) {
|
||||
app.use(function(req, res, next){
|
||||
next();
|
||||
});
|
||||
}
|
||||
|
||||
var body = new Buffer('Hello World');
|
||||
|
||||
app.use(function(req, res, next){
|
||||
res.send(body);
|
||||
});
|
||||
|
||||
app.listen(3333);
|
||||
16
benchmarks/run
Executable file
16
benchmarks/run
Executable file
@@ -0,0 +1,16 @@
|
||||
#!/usr/bin/env bash
|
||||
|
||||
echo
|
||||
MW=$1 node $2 &
|
||||
pid=$!
|
||||
|
||||
sleep 2
|
||||
|
||||
wrk 'http://localhost:3333/?foo[bar]=baz' \
|
||||
-d 3 \
|
||||
-c 50 \
|
||||
-t 8 \
|
||||
| grep 'Requests/sec' \
|
||||
| awk '{ print " " $2 }'
|
||||
|
||||
kill $pid
|
||||
29
bin/express
29
bin/express
@@ -4,8 +4,7 @@
|
||||
* Module dependencies.
|
||||
*/
|
||||
|
||||
var exec = require('child_process').exec
|
||||
, program = require('commander')
|
||||
var program = require('commander')
|
||||
, mkdirp = require('mkdirp')
|
||||
, pkg = require('../package.json')
|
||||
, version = pkg.version
|
||||
@@ -16,6 +15,7 @@ var exec = require('child_process').exec
|
||||
|
||||
program
|
||||
.version(version)
|
||||
.usage('[options] [dir]')
|
||||
.option('-s, --sessions', 'add session support')
|
||||
.option('-e, --ejs', 'add ejs engine support (defaults to jade)')
|
||||
.option('-J, --jshtml', 'add jshtml engine support (defaults to jade)')
|
||||
@@ -74,7 +74,7 @@ var users = [
|
||||
*/
|
||||
|
||||
var jadeLayout = [
|
||||
'doctype 5'
|
||||
'doctype html'
|
||||
, 'html'
|
||||
, ' head'
|
||||
, ' title= title'
|
||||
@@ -208,21 +208,22 @@ var app = [
|
||||
, ' * Module dependencies.'
|
||||
, ' */'
|
||||
, ''
|
||||
, 'var express = require(\'express\')'
|
||||
, ' , routes = require(\'./routes\')'
|
||||
, ' , user = require(\'./routes/user\')'
|
||||
, ' , http = require(\'http\')'
|
||||
, ' , path = require(\'path\');'
|
||||
, 'var express = require(\'express\');'
|
||||
, 'var routes = require(\'./routes\');'
|
||||
, 'var user = require(\'./routes/user\');'
|
||||
, 'var http = require(\'http\');'
|
||||
, 'var path = require(\'path\');'
|
||||
, ''
|
||||
, 'var app = express();'
|
||||
, ''
|
||||
, '// all environments'
|
||||
, 'app.set(\'port\', process.env.PORT || 3000);'
|
||||
, 'app.set(\'views\', __dirname + \'/views\');'
|
||||
, 'app.set(\'views\', path.join(__dirname, \'views\'));'
|
||||
, 'app.set(\'view engine\', \':TEMPLATE\');'
|
||||
, 'app.use(express.favicon());'
|
||||
, 'app.use(express.logger(\'dev\'));'
|
||||
, 'app.use(express.bodyParser());'
|
||||
, 'app.use(express.json());'
|
||||
, 'app.use(express.urlencoded());'
|
||||
, 'app.use(express.methodOverride());{sess}'
|
||||
, 'app.use(app.router);{css}'
|
||||
, 'app.use(express.static(path.join(__dirname, \'public\')));'
|
||||
@@ -323,10 +324,10 @@ function createApplicationAt(path) {
|
||||
// CSS Engine support
|
||||
switch (program.css) {
|
||||
case 'less':
|
||||
app = app.replace('{css}', eol + ' app.use(require(\'less-middleware\')({ src: __dirname + \'/public\' }));');
|
||||
app = app.replace('{css}', eol + 'app.use(require(\'less-middleware\')({ src: path.join(__dirname, \'public\') }));');
|
||||
break;
|
||||
case 'stylus':
|
||||
app = app.replace('{css}', eol + ' app.use(require(\'stylus\').middleware(__dirname + \'/public\'));');
|
||||
app = app.replace('{css}', eol + 'app.use(require(\'stylus\').middleware(path.join(__dirname, \'public\')));');
|
||||
break;
|
||||
default:
|
||||
app = app.replace('{css}', '');
|
||||
@@ -334,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
|
||||
@@ -356,7 +357,7 @@ function createApplicationAt(path) {
|
||||
// CSS Engine support
|
||||
switch (program.css) {
|
||||
case 'less':
|
||||
pkg.dependencies['less-middleware'] = '*';
|
||||
pkg.dependencies['less-middleware'] = '~0.1.15';
|
||||
break;
|
||||
default:
|
||||
if (program.css) {
|
||||
|
||||
@@ -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');
|
||||
|
||||
@@ -32,7 +32,7 @@ var iterations = 12000;
|
||||
exports.hash = function (pwd, salt, fn) {
|
||||
if (3 == arguments.length) {
|
||||
crypto.pbkdf2(pwd, salt, iterations, len, function(err, hash){
|
||||
fn(err, (new Buffer(hash, 'binary')).toString('base64'));
|
||||
fn(err, hash.toString('base64'));
|
||||
});
|
||||
} else {
|
||||
fn = salt;
|
||||
@@ -41,8 +41,8 @@ exports.hash = function (pwd, salt, fn) {
|
||||
salt = salt.toString('base64');
|
||||
crypto.pbkdf2(pwd, salt, iterations, len, function(err, hash){
|
||||
if (err) return fn(err);
|
||||
fn(null, salt, (new Buffer(hash, 'binary')).toString('base64'));
|
||||
fn(null, salt, hash.toString('base64'));
|
||||
});
|
||||
});
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
@@ -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');
|
||||
}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
style
|
||||
style.
|
||||
body {
|
||||
padding: 50px;
|
||||
font: 16px "Helvetica Neue", Helvetica;
|
||||
|
||||
@@ -1,8 +1,9 @@
|
||||
|
||||
var express = require('../../')
|
||||
, app = module.exports = express()
|
||||
, users = require('./db');
|
||||
|
||||
// so either you can deal with different types of formatting
|
||||
// for expected response in index.js
|
||||
app.get('/', function(req, res){
|
||||
res.format({
|
||||
html: function(){
|
||||
@@ -24,10 +25,11 @@ app.get('/', function(req, res){
|
||||
});
|
||||
|
||||
// or you could write a tiny middleware like
|
||||
// this to abstract make things a bit more declarative:
|
||||
// this to add a layer of abstraction
|
||||
// and make things a bit more declarative:
|
||||
|
||||
function format(mod) {
|
||||
var obj = require(mod);
|
||||
function format(path) {
|
||||
var obj = require(path);
|
||||
return function(req, res){
|
||||
res.format(obj);
|
||||
}
|
||||
@@ -35,7 +37,8 @@ function format(mod) {
|
||||
|
||||
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');
|
||||
}
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
html
|
||||
head
|
||||
title Express
|
||||
script
|
||||
script.
|
||||
// call this whatever you like,
|
||||
// or dump them into individual
|
||||
// props like "var user ="
|
||||
@@ -10,5 +10,5 @@ html
|
||||
h1 Expose client data
|
||||
p The following was exposed to the client:
|
||||
pre
|
||||
script
|
||||
script.
|
||||
document.write(JSON.stringify(data, null, 2))
|
||||
@@ -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');
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
!!! 5
|
||||
doctype html
|
||||
html
|
||||
include header
|
||||
body
|
||||
block content
|
||||
block content
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
|
||||
var express = require('../..')
|
||||
, fs = require('fs')
|
||||
, md = require('github-flavored-markdown').parse;
|
||||
, md = require('marked').parse;
|
||||
|
||||
var app = module.exports = express();
|
||||
|
||||
@@ -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');
|
||||
}
|
||||
}
|
||||
|
||||
@@ -20,7 +20,7 @@ exports.edit = function(req, res, next){
|
||||
|
||||
exports.update = function(req, res, next){
|
||||
var body = req.body;
|
||||
req.pet.name = body.user.name;
|
||||
req.pet.name = body.pet.name;
|
||||
res.message('Information updated!');
|
||||
res.redirect('/pet/' + req.pet.id);
|
||||
};
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
|
||||
var express = require('../..');
|
||||
|
||||
var app = module.exports = express();
|
||||
@@ -32,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());
|
||||
@@ -58,10 +56,10 @@ app.use(function(req, res, next){
|
||||
});
|
||||
*/
|
||||
|
||||
next();
|
||||
// empty or "flush" the messages so they
|
||||
// don't build up
|
||||
req.session.messages = [];
|
||||
next();
|
||||
});
|
||||
|
||||
// load controllers
|
||||
@@ -87,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.del(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');
|
||||
}
|
||||
}
|
||||
|
||||
@@ -29,7 +29,7 @@ var users = {
|
||||
res.send('user ' + req.params.uid);
|
||||
},
|
||||
|
||||
del: function(req, res){
|
||||
delete: function(req, res){
|
||||
res.send('delete users');
|
||||
}
|
||||
};
|
||||
@@ -39,7 +39,7 @@ var pets = {
|
||||
res.send('user ' + req.params.uid + '\'s pets');
|
||||
},
|
||||
|
||||
del: function(req, res){
|
||||
delete: function(req, res){
|
||||
res.send('delete ' + req.params.uid + '\'s pet ' + req.params.pid);
|
||||
}
|
||||
};
|
||||
@@ -47,17 +47,21 @@ var pets = {
|
||||
app.map({
|
||||
'/users': {
|
||||
get: users.list,
|
||||
del: users.del,
|
||||
delete: users.delete,
|
||||
'/:uid': {
|
||||
get: users.get,
|
||||
'/pets': {
|
||||
get: pets.list,
|
||||
'/:pid': {
|
||||
del: pets.del
|
||||
delete: pets.delete
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
app.listen(3000);
|
||||
/* istanbul ignore next */
|
||||
if (!module.parent) {
|
||||
app.listen(3000);
|
||||
console.log('Express started on port 3000');
|
||||
}
|
||||
|
||||
@@ -77,9 +77,12 @@ app.get('/user/:id/edit', loadUser, andRestrictToSelf, function(req, res){
|
||||
res.send('Editing user ' + req.user.name);
|
||||
});
|
||||
|
||||
app.del('/user/:id', loadUser, andRestrictTo('admin'), function(req, res){
|
||||
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');
|
||||
}
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
html
|
||||
head
|
||||
title Search example
|
||||
style
|
||||
style.
|
||||
body {
|
||||
font: 14px "Helvetica Neue", Helvetica;
|
||||
padding: 50px;
|
||||
|
||||
@@ -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 = '';
|
||||
|
||||
@@ -12,7 +12,7 @@ edit /etc/hosts:
|
||||
127.0.0.1 example.com
|
||||
*/
|
||||
|
||||
// Main app
|
||||
// Main server app
|
||||
|
||||
var main = express();
|
||||
|
||||
@@ -23,7 +23,7 @@ main.get('/', function(req, res){
|
||||
});
|
||||
|
||||
main.get('/:sub', function(req, res){
|
||||
res.send('requsted ' + req.params.sub);
|
||||
res.send('requested ' + req.params.sub);
|
||||
});
|
||||
|
||||
// Redirect app
|
||||
@@ -35,12 +35,15 @@ redirect.all('*', function(req, res){
|
||||
res.redirect('http://example.com:3000/' + req.subdomains[0]);
|
||||
});
|
||||
|
||||
// Main app
|
||||
// Vhost app
|
||||
|
||||
var app = express();
|
||||
|
||||
app.use(express.vhost('*.example.com', redirect))
|
||||
app.use(express.vhost('example.com', main));
|
||||
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 });
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
var express = require('../../')
|
||||
, http = require('http')
|
||||
, GithubView = require('./github-view')
|
||||
, md = require('github-flavored-markdown').parse;
|
||||
, md = require('marked').parse;
|
||||
|
||||
var app = module.exports = express();
|
||||
|
||||
@@ -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');
|
||||
}
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
doctype 5
|
||||
doctype html
|
||||
html
|
||||
head
|
||||
title= title
|
||||
style
|
||||
style.
|
||||
body {
|
||||
padding: 50px;
|
||||
font: 16px Helvetica, Arial;
|
||||
|
||||
@@ -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');
|
||||
}
|
||||
|
||||
4
index.js
4
index.js
@@ -1,4 +1,2 @@
|
||||
|
||||
module.exports = process.env.EXPRESS_COV
|
||||
? require('./lib-cov/express')
|
||||
: require('./lib/express');
|
||||
module.exports = require('./lib/express');
|
||||
|
||||
@@ -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
|
||||
, path = require('path')
|
||||
, http = require('http')
|
||||
, join = path.join;
|
||||
, http = require('http');
|
||||
var deprecate = require('depd')('express');
|
||||
|
||||
/**
|
||||
* Application prototype.
|
||||
@@ -46,9 +47,13 @@ app.init = function(){
|
||||
app.defaultConfiguration = function(){
|
||||
// default settings
|
||||
this.enable('x-powered-by');
|
||||
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);
|
||||
debug('booting in %s mode', this.get('env'));
|
||||
this.set('trust proxy', false);
|
||||
|
||||
debug('booting in %s mode', env);
|
||||
|
||||
// implicit middleware
|
||||
this.use(connect.query());
|
||||
@@ -83,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');
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -117,7 +122,6 @@ app.use = function(route, fn){
|
||||
fn = function(req, res, next) {
|
||||
var orig = req.app;
|
||||
app.handle(req, res, function(err){
|
||||
req.app = res.app = orig;
|
||||
req.__proto__ = orig.request;
|
||||
res.__proto__ = orig.response;
|
||||
next(err);
|
||||
@@ -185,7 +189,7 @@ app.engine = function(ext, fn){
|
||||
* could automatically load a user's information from the database without
|
||||
* any additional code,
|
||||
*
|
||||
* The callback uses the samesignature as middleware, the only differencing
|
||||
* The callback uses the same signature as middleware, the only difference
|
||||
* being that the value of the placeholder is passed, in this case the _id_
|
||||
* of the user. Once the `next()` function is invoked, just like middleware
|
||||
* it will continue on to execute the route, or subsequent parameter functions.
|
||||
@@ -244,18 +248,33 @@ app.param = function(name, fn){
|
||||
* Mounted servers inherit their parent server's settings.
|
||||
*
|
||||
* @param {String} setting
|
||||
* @param {String} val
|
||||
* @param {*} [val]
|
||||
* @return {Server} for chaining
|
||||
* @api public
|
||||
*/
|
||||
|
||||
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;
|
||||
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;
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -394,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(...)`.
|
||||
*/
|
||||
@@ -402,11 +424,6 @@ methods.forEach(function(method){
|
||||
app[method] = function(path){
|
||||
if ('get' == method && 1 == arguments.length) return this.set(path);
|
||||
|
||||
// deprecated
|
||||
if (Array.isArray(path)) {
|
||||
console.trace('passing an array to app.VERB() is deprecated and will be removed in 4.0');
|
||||
}
|
||||
|
||||
// if no router attached yet, attach the router
|
||||
if (!this._usedRouter) this.use(this.router);
|
||||
|
||||
@@ -436,7 +453,7 @@ app.all = function(path){
|
||||
|
||||
// del -> delete alias
|
||||
|
||||
app.del = app.delete;
|
||||
app.del = deprecate.function(app.delete, 'app.del: Use app.delete instead');
|
||||
|
||||
/**
|
||||
* Render the given view `name` name with `options`
|
||||
@@ -492,7 +509,7 @@ app.render = function(name, options, fn){
|
||||
});
|
||||
|
||||
if (!view.path) {
|
||||
var err = new Error('Failed to lookup view "' + name + '"');
|
||||
var err = new Error('Failed to lookup view "' + name + '" in views directory "' + view.root + '"');
|
||||
err.view = view;
|
||||
return fn(err);
|
||||
}
|
||||
|
||||
@@ -2,6 +2,8 @@
|
||||
* Module dependencies.
|
||||
*/
|
||||
|
||||
var deprecate = require('depd')('express');
|
||||
var merge = require('merge-descriptors');
|
||||
var connect = require('connect')
|
||||
, proto = require('./application')
|
||||
, Route = require('./router/route')
|
||||
@@ -16,12 +18,6 @@ var connect = require('connect')
|
||||
|
||||
exports = module.exports = createApplication;
|
||||
|
||||
/**
|
||||
* Framework version.
|
||||
*/
|
||||
|
||||
exports.version = '3.2.4';
|
||||
|
||||
/**
|
||||
* Expose mime.
|
||||
*/
|
||||
@@ -38,8 +34,8 @@ exports.mime = connect.mime;
|
||||
function createApplication() {
|
||||
var app = connect();
|
||||
utils.merge(app, proto);
|
||||
app.request = { __proto__: req };
|
||||
app.response = { __proto__: res };
|
||||
app.request = { __proto__: req, app: app };
|
||||
app.response = { __proto__: res, app: app };
|
||||
app.init();
|
||||
return app;
|
||||
}
|
||||
@@ -49,27 +45,21 @@ function createApplication() {
|
||||
* for example `express.logger` etc.
|
||||
*/
|
||||
|
||||
for (var key in connect.middleware) {
|
||||
Object.defineProperty(
|
||||
exports
|
||||
, key
|
||||
, Object.getOwnPropertyDescriptor(connect.middleware, key));
|
||||
}
|
||||
merge(exports, connect.middleware);
|
||||
|
||||
/**
|
||||
* Error on createServer().
|
||||
* Deprecated createServer().
|
||||
*/
|
||||
|
||||
exports.createServer = function(){
|
||||
console.warn('Warning: express.createServer() is deprecated, express');
|
||||
console.warn('applications no longer inherit from http.Server,');
|
||||
console.warn('please use:');
|
||||
console.warn('');
|
||||
console.warn(' var express = require("express");');
|
||||
console.warn(' var app = express();');
|
||||
console.warn('');
|
||||
return createApplication();
|
||||
};
|
||||
exports.createServer = deprecate.function(createApplication,
|
||||
'createServer() is deprecated\n' +
|
||||
'express applications no longer inherit from http.Server\n' +
|
||||
'please use:\n' +
|
||||
'\n' +
|
||||
' var express = require("express");\n' +
|
||||
' var app = express();\n' +
|
||||
'\n'
|
||||
);
|
||||
|
||||
/**
|
||||
* Expose the prototypes.
|
||||
|
||||
@@ -17,7 +17,6 @@ var utils = require('./utils');
|
||||
|
||||
exports.init = function(app){
|
||||
return function expressInit(req, res, next){
|
||||
req.app = res.app = app;
|
||||
if (app.enabled('x-powered-by')) res.setHeader('X-Powered-By', 'Express');
|
||||
req.res = res;
|
||||
res.req = req;
|
||||
|
||||
123
lib/request.js
123
lib/request.js
@@ -3,13 +3,17 @@
|
||||
* Module dependencies.
|
||||
*/
|
||||
|
||||
var auth = require('basic-auth');
|
||||
var deprecate = require('depd')('express');
|
||||
var http = require('http')
|
||||
, utils = require('./utils')
|
||||
, connect = require('connect')
|
||||
, fresh = require('fresh')
|
||||
, parseRange = require('range-parser')
|
||||
, parse = connect.utils.parseUrl
|
||||
, parse = require('parseurl')
|
||||
, proxyaddr = require('proxy-addr')
|
||||
, mime = connect.mime;
|
||||
var isIP = require('net').isIP;
|
||||
|
||||
/**
|
||||
* Request prototype.
|
||||
@@ -63,6 +67,7 @@ req.header = function(name){
|
||||
* The `type` value may be a single mime type string
|
||||
* such as "application/json", the extension name
|
||||
* such as "json", a comma-delimted list such as "json, html, text/plain",
|
||||
* an argument list such as `"json", "html", "text/plain"`,
|
||||
* or an array `["json", "html", "text/plain"]`. When a list
|
||||
* or array is given the _best_ match, if any is returned.
|
||||
*
|
||||
@@ -89,6 +94,7 @@ req.header = function(name){
|
||||
*
|
||||
* // Accept: text/*;q=.5, application/json
|
||||
* req.accepts(['html', 'json']);
|
||||
* req.accepts('html', 'json');
|
||||
* req.accepts('html, json');
|
||||
* // => "json"
|
||||
*
|
||||
@@ -98,7 +104,8 @@ req.header = function(name){
|
||||
*/
|
||||
|
||||
req.accepts = function(type){
|
||||
return utils.accepts(type, this.get('Accept'));
|
||||
var args = arguments.length > 1 ? [].slice.apply(arguments) : type;
|
||||
return utils.accepts(args, this.get('Accept'));
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -110,7 +117,7 @@ req.accepts = function(type){
|
||||
*/
|
||||
|
||||
req.acceptsEncoding = function(encoding){
|
||||
return ~this.acceptedEncodings.indexOf(encoding);
|
||||
return !! ~this.acceptedEncodings.indexOf(encoding);
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -125,7 +132,7 @@ req.acceptsEncoding = function(encoding){
|
||||
req.acceptsCharset = function(charset){
|
||||
var accepted = this.acceptedCharsets;
|
||||
return accepted.length
|
||||
? ~accepted.indexOf(charset)
|
||||
? !! ~accepted.indexOf(charset)
|
||||
: true;
|
||||
};
|
||||
|
||||
@@ -141,7 +148,7 @@ req.acceptsCharset = function(charset){
|
||||
req.acceptsLanguage = function(lang){
|
||||
var accepted = this.acceptedLanguages;
|
||||
return accepted.length
|
||||
? ~accepted.indexOf(lang)
|
||||
? !! ~accepted.indexOf(lang)
|
||||
: true;
|
||||
};
|
||||
|
||||
@@ -334,22 +341,31 @@ req.is = function(type){
|
||||
/**
|
||||
* Return the protocol string "http" or "https"
|
||||
* when requested with TLS. When the "trust proxy"
|
||||
* setting is enabled the "X-Forwarded-Proto" header
|
||||
* field will be trusted. If you're running behind
|
||||
* a reverse proxy that supplies https for you this
|
||||
* may be enabled.
|
||||
* setting trusts the socket address, the
|
||||
* "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.
|
||||
*
|
||||
* @return {String}
|
||||
* @api public
|
||||
*/
|
||||
|
||||
req.__defineGetter__('protocol', function(){
|
||||
var trustProxy = this.app.get('trust proxy');
|
||||
return this.connection.encrypted
|
||||
var proto = this.connection.encrypted
|
||||
? 'https'
|
||||
: trustProxy
|
||||
? (this.get('X-Forwarded-Proto') || 'http')
|
||||
: 'http';
|
||||
: 'http';
|
||||
var trust = this.app.get('trust proxy fn');
|
||||
|
||||
if (!trust(this.connection.remoteAddress)) {
|
||||
return proto;
|
||||
}
|
||||
|
||||
// Note: X-Forwarded-Proto is normally only ever a
|
||||
// single value, but this is to be safe.
|
||||
proto = this.get('X-Forwarded-Proto') || proto;
|
||||
return proto.split(/\s*,\s*/)[0];
|
||||
});
|
||||
|
||||
/**
|
||||
@@ -366,36 +382,36 @@ req.__defineGetter__('secure', function(){
|
||||
});
|
||||
|
||||
/**
|
||||
* Return the remote address, or when
|
||||
* "trust proxy" is `true` return
|
||||
* the upstream addr.
|
||||
* Return the remote address from the trusted proxy.
|
||||
*
|
||||
* The is the remote address on the socket unless
|
||||
* "trust proxy" is set.
|
||||
*
|
||||
* @return {String}
|
||||
* @api public
|
||||
*/
|
||||
|
||||
req.__defineGetter__('ip', function(){
|
||||
return this.ips[0] || this.connection.remoteAddress;
|
||||
var trust = this.app.get('trust proxy fn');
|
||||
return proxyaddr(this, trust);
|
||||
});
|
||||
|
||||
/**
|
||||
* When "trust proxy" is `true`, parse
|
||||
* the "X-Forwarded-For" ip address list.
|
||||
* When "trust proxy" is set, trusted proxy addresses + client.
|
||||
*
|
||||
* For example if the value were "client, proxy1, proxy2"
|
||||
* you would receive the array `["client", "proxy1", "proxy2"]`
|
||||
* where "proxy2" is the furthest down-stream.
|
||||
* where "proxy2" is the furthest down-stream and "proxy1" and
|
||||
* "proxy2" were trusted.
|
||||
*
|
||||
* @return {Array}
|
||||
* @api public
|
||||
*/
|
||||
|
||||
req.__defineGetter__('ips', function(){
|
||||
var trustProxy = this.app.get('trust proxy');
|
||||
var val = this.get('X-Forwarded-For');
|
||||
return trustProxy && val
|
||||
? val.split(/ *, */)
|
||||
: [];
|
||||
var trust = this.app.get('trust proxy fn');
|
||||
var addrs = proxyaddr.all(this, trust);
|
||||
return addrs.slice(1).reverse();
|
||||
});
|
||||
|
||||
/**
|
||||
@@ -412,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 };
|
||||
});
|
||||
|
||||
/**
|
||||
@@ -444,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);
|
||||
});
|
||||
|
||||
/**
|
||||
@@ -465,16 +479,33 @@ req.__defineGetter__('path', function(){
|
||||
/**
|
||||
* Parse the "Host" header field hostname.
|
||||
*
|
||||
* When the "trust proxy" setting trusts the socket
|
||||
* address, the "X-Forwarded-Host" header field will
|
||||
* be trusted.
|
||||
*
|
||||
* @return {String}
|
||||
* @api public
|
||||
*/
|
||||
|
||||
req.__defineGetter__('host', function(){
|
||||
var trustProxy = this.app.get('trust proxy');
|
||||
var host = trustProxy && this.get('X-Forwarded-Host');
|
||||
host = host || this.get('Host');
|
||||
var trust = this.app.get('trust proxy fn');
|
||||
var host = this.get('X-Forwarded-Host');
|
||||
|
||||
if (!host || !trust(this.connection.remoteAddress)) {
|
||||
host = this.get('Host');
|
||||
}
|
||||
|
||||
if (!host) return;
|
||||
return host.split(':')[0];
|
||||
|
||||
// IPv6 literal support
|
||||
var offset = host[0] === '['
|
||||
? host.indexOf(']') + 1
|
||||
: 0;
|
||||
var index = host.indexOf(':', offset);
|
||||
|
||||
return ~index
|
||||
? host.substring(0, index)
|
||||
: host;
|
||||
});
|
||||
|
||||
/**
|
||||
|
||||
186
lib/response.js
186
lib/response.js
@@ -2,6 +2,10 @@
|
||||
* Module dependencies.
|
||||
*/
|
||||
|
||||
var deprecate = require('depd')('express');
|
||||
var escapeHtml = require('escape-html');
|
||||
var parseUrl = require('parseurl');
|
||||
var vary = require('vary');
|
||||
var http = require('http')
|
||||
, path = require('path')
|
||||
, connect = require('connect')
|
||||
@@ -9,14 +13,14 @@ var http = require('http')
|
||||
, sign = require('cookie-signature').sign
|
||||
, normalizeType = require('./utils').normalizeType
|
||||
, normalizeTypes = require('./utils').normalizeTypes
|
||||
, etag = require('./utils').etag
|
||||
, setCharset = require('./utils').setCharset
|
||||
, statusCodes = http.STATUS_CODES
|
||||
, cookie = require('cookie')
|
||||
, send = require('send')
|
||||
, mime = connect.mime
|
||||
, resolve = require('url').resolve
|
||||
, basename = path.basename
|
||||
, extname = path.extname
|
||||
, join = path.join;
|
||||
, extname = path.extname;
|
||||
|
||||
/**
|
||||
* Response prototype.
|
||||
@@ -55,7 +59,9 @@ res.status = function(code){
|
||||
*/
|
||||
|
||||
res.links = function(links){
|
||||
return this.set('Link', Object.keys(links).map(function(rel){
|
||||
var link = this.get('Link') || '';
|
||||
if (link) link += ', ';
|
||||
return this.set('Link', link + Object.keys(links).map(function(rel){
|
||||
return '<' + links[rel] + '>; rel="' + rel + '"';
|
||||
}).join(', '));
|
||||
};
|
||||
@@ -78,9 +84,14 @@ res.links = function(links){
|
||||
*/
|
||||
|
||||
res.send = function(body){
|
||||
var req = this.req
|
||||
, head = 'HEAD' == req.method
|
||||
, len;
|
||||
var req = this.req;
|
||||
var head = 'HEAD' == req.method;
|
||||
var type;
|
||||
var encoding;
|
||||
var len;
|
||||
|
||||
// settings
|
||||
var app = this.app;
|
||||
|
||||
// allow status / body
|
||||
if (2 == arguments.length) {
|
||||
@@ -93,13 +104,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')) {
|
||||
@@ -108,6 +121,7 @@ res.send = function(body){
|
||||
}
|
||||
break;
|
||||
case 'boolean':
|
||||
case 'number':
|
||||
case 'object':
|
||||
if (null == body) {
|
||||
body = '';
|
||||
@@ -119,18 +133,31 @@ res.send = function(body){
|
||||
break;
|
||||
}
|
||||
|
||||
// write strings in utf-8
|
||||
if ('string' === typeof body) {
|
||||
encoding = 'utf8';
|
||||
type = this.get('Content-Type');
|
||||
|
||||
// reflect this in content-type
|
||||
if ('string' === typeof type) {
|
||||
this.set('Content-Type', setCharset(type, 'utf-8'));
|
||||
}
|
||||
}
|
||||
|
||||
// populate Content-Length
|
||||
if (undefined !== body && !this.get('Content-Length')) {
|
||||
this.set('Content-Length', len = Buffer.isBuffer(body)
|
||||
len = Buffer.isBuffer(body)
|
||||
? body.length
|
||||
: Buffer.byteLength(body));
|
||||
: Buffer.byteLength(body, encoding);
|
||||
this.set('Content-Length', len);
|
||||
}
|
||||
|
||||
// ETag support
|
||||
// TODO: W/ support
|
||||
if (len > 1024) {
|
||||
var etag = len !== undefined && app.get('etag fn');
|
||||
if (etag && ('GET' === req.method || 'HEAD' === req.method)) {
|
||||
if (!this.get('ETag')) {
|
||||
this.set('ETag', etag(body));
|
||||
etag = etag(body, encoding);
|
||||
etag && this.set('ETag', etag);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -146,7 +173,8 @@ res.send = function(body){
|
||||
}
|
||||
|
||||
// respond
|
||||
this.end(head ? null : body);
|
||||
this.end((head ? null : body), encoding);
|
||||
|
||||
return this;
|
||||
};
|
||||
|
||||
@@ -172,6 +200,11 @@ res.json = function(obj){
|
||||
// res.json(body, status) backwards compat
|
||||
if ('number' == typeof arguments[1]) {
|
||||
this.statusCode = arguments[1];
|
||||
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];
|
||||
@@ -213,6 +246,11 @@ res.jsonp = function(obj){
|
||||
// res.json(body, status) backwards compat
|
||||
if ('number' == typeof arguments[1]) {
|
||||
this.statusCode = arguments[1];
|
||||
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];
|
||||
@@ -223,20 +261,38 @@ 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.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)) {
|
||||
callback = callback[0];
|
||||
}
|
||||
|
||||
// jsonp
|
||||
if (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 = cb + ' && ' + 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);
|
||||
@@ -253,8 +309,11 @@ res.jsonp = function(obj){
|
||||
*
|
||||
* 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:
|
||||
*
|
||||
@@ -305,23 +364,23 @@ res.sendfile = function(path, options, fn){
|
||||
|
||||
// clean up
|
||||
cleanup();
|
||||
if (!self.headerSent) self.removeHeader('Content-Disposition');
|
||||
if (!self.headersSent) self.removeHeader('Content-Disposition');
|
||||
|
||||
// callback available
|
||||
if (fn) return fn(err);
|
||||
|
||||
// list in limbo if there's no callback
|
||||
if (self.headerSent) return;
|
||||
if (self.headersSent) return;
|
||||
|
||||
// delegate
|
||||
next(err);
|
||||
}
|
||||
|
||||
// streaming
|
||||
function stream() {
|
||||
function stream(stream) {
|
||||
if (done) return;
|
||||
cleanup();
|
||||
if (fn) self.on('finish', fn);
|
||||
if (fn) stream.on('end', fn);
|
||||
}
|
||||
|
||||
// cleanup
|
||||
@@ -330,9 +389,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);
|
||||
@@ -346,7 +403,7 @@ res.sendfile = function(path, options, fn){
|
||||
* Optionally providing an alternate attachment `filename`,
|
||||
* and optional callback `fn(err)`. The callback is invoked
|
||||
* when the data transfer is complete, or when an error has
|
||||
* ocurred. Be sure to check `res.headerSent` if you plan to respond.
|
||||
* ocurred. Be sure to check `res.headersSent` if you plan to respond.
|
||||
*
|
||||
* This method uses `res.sendfile()`.
|
||||
*
|
||||
@@ -459,10 +516,13 @@ res.format = function(obj){
|
||||
|
||||
var key = req.accepts(keys);
|
||||
|
||||
this.set('Vary', 'Accept');
|
||||
this.vary("Accept");
|
||||
|
||||
if (key) {
|
||||
this.set('Content-Type', normalizeType(key).value);
|
||||
var type = normalizeType(key).value;
|
||||
var charset = mime.charsets.lookup(type);
|
||||
if (charset) type += '; charset=' + charset;
|
||||
this.set('Content-Type', type);
|
||||
obj[key](req, this, next);
|
||||
} else if (fn) {
|
||||
fn();
|
||||
@@ -596,8 +656,7 @@ res.cookie = function(name, val, options){
|
||||
/**
|
||||
* Set the location header to `url`.
|
||||
*
|
||||
* The given `url` can also be the name of a mapped url, for
|
||||
* example by default express supports "back" which redirects
|
||||
* The given `url` can also be "back", which redirects
|
||||
* to the _Referrer_ or _Referer_ headers or "/".
|
||||
*
|
||||
* Examples:
|
||||
@@ -625,22 +684,19 @@ res.cookie = function(name, val, options){
|
||||
|
||||
res.location = function(url){
|
||||
var app = this.app
|
||||
, req = this.req;
|
||||
, req = this.req
|
||||
, path;
|
||||
|
||||
// setup redirect map
|
||||
var map = { back: req.get('Referrer') || '/' };
|
||||
|
||||
// perform redirect
|
||||
url = map[url] || url;
|
||||
// "back" is an alias for the referrer
|
||||
if ('back' == url) url = req.get('Referrer') || '/';
|
||||
|
||||
// relative
|
||||
if (!~url.indexOf('://') && 0 != url.indexOf('//')) {
|
||||
var path
|
||||
|
||||
// relative to path
|
||||
if ('.' == url[0]) {
|
||||
path = req.originalUrl.split('?')[0]
|
||||
url = path + ('/' == path[path.length - 1] ? '' : '/') + url;
|
||||
path = parseUrl.original(req).pathname;
|
||||
path = path + ('/' == path[path.length - 1] ? '' : '/');
|
||||
url = resolve(path, url);
|
||||
// relative to mount-point
|
||||
} else if ('/' != url[0]) {
|
||||
path = app.path();
|
||||
@@ -666,17 +722,13 @@ 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
|
||||
*/
|
||||
|
||||
res.redirect = function(url){
|
||||
var app = this.app
|
||||
, head = 'HEAD' == this.req.method
|
||||
var head = 'HEAD' == this.req.method
|
||||
, status = 302
|
||||
, body;
|
||||
|
||||
@@ -686,6 +738,7 @@ res.redirect = function(url){
|
||||
status = url;
|
||||
url = arguments[1];
|
||||
} else {
|
||||
deprecate('res.redirect(ur, status): Use res.redirect(status, url) instead');
|
||||
status = arguments[1];
|
||||
}
|
||||
}
|
||||
@@ -701,7 +754,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>';
|
||||
},
|
||||
|
||||
@@ -716,6 +769,25 @@ res.redirect = function(url){
|
||||
this.end(head ? null : body);
|
||||
};
|
||||
|
||||
/**
|
||||
* Add `field` to Vary. If already present in the Vary set, then
|
||||
* this call is simply ignored.
|
||||
*
|
||||
* @param {Array|String} field
|
||||
* @param {ServerResponse} for chaining
|
||||
* @api public
|
||||
*/
|
||||
|
||||
res.vary = function(field){
|
||||
// checks for back-compat
|
||||
if (!field) return this;
|
||||
if (Array.isArray(field) && !field.length) return this;
|
||||
|
||||
vary(this, field);
|
||||
|
||||
return this;
|
||||
};
|
||||
|
||||
/**
|
||||
* Render `view` with the given `options` and optional callback `fn`.
|
||||
* When a callback function is given a response will _not_ be made
|
||||
|
||||
@@ -2,11 +2,11 @@
|
||||
* Module dependencies.
|
||||
*/
|
||||
|
||||
var Route = require('./route')
|
||||
, utils = require('../utils')
|
||||
, methods = require('methods')
|
||||
, debug = require('debug')('express:router')
|
||||
, parse = require('connect').utils.parseUrl;
|
||||
var Route = require('./route');
|
||||
var utils = require('../utils');
|
||||
var methods = require('methods');
|
||||
var debug = require('debug')('express:router');
|
||||
var parseUrl = require('parseurl');
|
||||
|
||||
/**
|
||||
* Expose `Router` constructor.
|
||||
@@ -103,6 +103,9 @@ Router.prototype._dispatch = function(req, res, next){
|
||||
// match route
|
||||
req.route = route = self.matchRequest(req, i);
|
||||
|
||||
// implied OPTIONS
|
||||
if (!route && 'OPTIONS' == req.method) return self._options(req, res, next);
|
||||
|
||||
// no route
|
||||
if (!route) return next(err);
|
||||
debug('matched %s %s', route.method, route.path);
|
||||
@@ -170,6 +173,42 @@ Router.prototype._dispatch = function(req, res, next){
|
||||
})(0);
|
||||
};
|
||||
|
||||
/**
|
||||
* Respond to __OPTIONS__ method.
|
||||
*
|
||||
* @param {IncomingMessage} req
|
||||
* @param {ServerResponse} res
|
||||
* @api private
|
||||
*/
|
||||
|
||||
Router.prototype._options = function(req, res, next){
|
||||
var path = parseUrl(req).pathname
|
||||
, body = this._optionsFor(path).join(',');
|
||||
if (!body) return next();
|
||||
res.set('Allow', body).send(body);
|
||||
};
|
||||
|
||||
/**
|
||||
* Return an array of HTTP verbs or "options" for `path`.
|
||||
*
|
||||
* @param {String} path
|
||||
* @return {Array}
|
||||
* @api private
|
||||
*/
|
||||
|
||||
Router.prototype._optionsFor = function(path){
|
||||
var self = this;
|
||||
return methods.filter(function(method){
|
||||
var routes = self.map[method];
|
||||
if (!routes || 'options' == method) return;
|
||||
for (var i = 0, len = routes.length; i < len; ++i) {
|
||||
if (routes[i].match(path)) return true;
|
||||
}
|
||||
}).map(function(method){
|
||||
return method.toUpperCase();
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* Attempt to match a route for `req`
|
||||
* with optional starting index of `i`
|
||||
@@ -183,7 +222,7 @@ Router.prototype._dispatch = function(req, res, next){
|
||||
|
||||
Router.prototype.matchRequest = function(req, i, head){
|
||||
var method = req.method.toLowerCase()
|
||||
, url = parse(req)
|
||||
, url = parseUrl(req)
|
||||
, path = url.pathname
|
||||
, routes = this.map
|
||||
, i = i || 0
|
||||
@@ -245,7 +284,7 @@ Router.prototype.route = function(method, path, callbacks){
|
||||
if (!path) throw new Error('Router#' + method + '() requires a path');
|
||||
|
||||
// ensure all callbacks are functions
|
||||
callbacks.forEach(function(fn, i){
|
||||
callbacks.forEach(function(fn){
|
||||
if ('function' == typeof fn) return;
|
||||
var type = {}.toString.call(fn);
|
||||
var msg = '.' + method + '() requires callback functions but got a ' + type;
|
||||
@@ -264,6 +303,15 @@ Router.prototype.route = function(method, path, callbacks){
|
||||
return this;
|
||||
};
|
||||
|
||||
Router.prototype.all = function(path) {
|
||||
var self = this;
|
||||
var args = [].slice.call(arguments);
|
||||
methods.forEach(function(method){
|
||||
self.route.apply(self, [method].concat(args));
|
||||
});
|
||||
return this;
|
||||
};
|
||||
|
||||
methods.forEach(function(method){
|
||||
Router.prototype[method] = function(path){
|
||||
var args = [method].concat([].slice.call(arguments));
|
||||
|
||||
@@ -57,9 +57,15 @@ Route.prototype.match = function(path){
|
||||
for (var i = 1, len = m.length; i < len; ++i) {
|
||||
var key = keys[i - 1];
|
||||
|
||||
var val = 'string' == typeof m[i]
|
||||
? decodeURIComponent(m[i])
|
||||
: m[i];
|
||||
try {
|
||||
var val = 'string' == typeof m[i]
|
||||
? decodeURIComponent(m[i])
|
||||
: m[i];
|
||||
} catch(e) {
|
||||
var err = new Error("Failed to decode param '" + m[i] + "'");
|
||||
err.status = 400;
|
||||
throw err;
|
||||
}
|
||||
|
||||
if (key) {
|
||||
params[key.name] = val;
|
||||
|
||||
147
lib/utils.js
147
lib/utils.js
@@ -3,8 +3,11 @@
|
||||
* Module dependencies.
|
||||
*/
|
||||
|
||||
var crc = require('crc').crc32;
|
||||
var mime = require('connect').mime
|
||||
, crc32 = require('buffer-crc32');
|
||||
, proxyaddr = require('proxy-addr')
|
||||
, crypto = require('crypto');
|
||||
var typer = require('media-typer');
|
||||
|
||||
/**
|
||||
* toString ref.
|
||||
@@ -13,15 +16,47 @@ var mime = require('connect').mime
|
||||
var toString = {}.toString;
|
||||
|
||||
/**
|
||||
* 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 etag(body, encoding){
|
||||
if (body.length === 0) {
|
||||
// fast-path empty body
|
||||
return '"1B2M2Y8AsgTpgAmY7PhCfg=="'
|
||||
}
|
||||
|
||||
var hash = crypto
|
||||
.createHash('md5')
|
||||
.update(body, encoding)
|
||||
.digest('base64')
|
||||
return '"' + hash + '"'
|
||||
};
|
||||
|
||||
/**
|
||||
* Return weak ETag for `body`.
|
||||
*
|
||||
* @param {String|Buffer} body
|
||||
* @param {String} [encoding]
|
||||
* @return {String}
|
||||
* @api private
|
||||
*/
|
||||
|
||||
exports.wetag = function wetag(body, encoding){
|
||||
if (body.length === 0) {
|
||||
// fast-path empty body
|
||||
return 'W/"0-0"'
|
||||
}
|
||||
|
||||
var buf = Buffer.isBuffer(body)
|
||||
? body
|
||||
: new Buffer(body, encoding)
|
||||
var len = buf.length
|
||||
return 'W/"' + len.toString(16) + '-' + crc(buf) + '"'
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -34,7 +69,7 @@ exports.etag = function(body){
|
||||
* @api private
|
||||
*/
|
||||
|
||||
exports.locals = function(obj){
|
||||
exports.locals = function(){
|
||||
function locals(obj){
|
||||
for (var key in obj) locals[key] = obj[key];
|
||||
return obj;
|
||||
@@ -54,6 +89,7 @@ exports.locals = function(obj){
|
||||
exports.isAbsolute = function(path){
|
||||
if ('/' == path[0]) return true;
|
||||
if (':' == path[1] && '\\' == path[2]) return true;
|
||||
if ('\\\\' == path.substring(0, 2)) return true; // Microsoft Azure absolute path
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -257,22 +293,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.
|
||||
@@ -311,3 +331,88 @@ exports.pathRegexp = function(path, keys, sensitive, strict) {
|
||||
.replace(/\*/g, '(.*)');
|
||||
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.
|
||||
*
|
||||
* @param {Boolean|String|Number|Array|Function} val
|
||||
* @return {Function}
|
||||
* @api private
|
||||
*/
|
||||
|
||||
exports.compileTrust = function(val) {
|
||||
if (typeof val === 'function') return val;
|
||||
|
||||
if (val === true) {
|
||||
// Support plain true/false
|
||||
return function(){ return true };
|
||||
}
|
||||
|
||||
if (typeof val === 'number') {
|
||||
// Support trusting hop count
|
||||
return function(a, i){ return i < val };
|
||||
}
|
||||
|
||||
if (typeof val === 'string') {
|
||||
// Support comma-separated values
|
||||
val = val.split(/ *, */);
|
||||
}
|
||||
|
||||
return proxyaddr.compile(val || []);
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the charset in a given Content-Type string.
|
||||
*
|
||||
* @param {String} type
|
||||
* @param {String} charset
|
||||
* @return {String}
|
||||
* @api private
|
||||
*/
|
||||
|
||||
exports.setCharset = function(type, charset){
|
||||
if (!type || !charset) return type;
|
||||
|
||||
// parse type
|
||||
var parsed = typer.parse(type);
|
||||
|
||||
// set charset
|
||||
parsed.parameters.charset = charset;
|
||||
|
||||
// format type
|
||||
return typer.format(parsed);
|
||||
};
|
||||
|
||||
@@ -38,6 +38,7 @@ function View(name, options) {
|
||||
var engines = options.engines;
|
||||
this.defaultEngine = options.defaultEngine;
|
||||
var ext = this.ext = extname(name);
|
||||
if (!ext && !this.defaultEngine) throw new Error('No default engine was specified and no extension was provided.');
|
||||
if (!ext) name += (ext = this.ext = ('.' != this.defaultEngine[0] ? '.' : '') + this.defaultEngine);
|
||||
this.engine = engines[ext] || (engines[ext] = require(ext.slice(1)).__express);
|
||||
this.path = this.lookup(name);
|
||||
|
||||
96
package.json
96
package.json
@@ -1,50 +1,16 @@
|
||||
{
|
||||
"name": "express",
|
||||
"description": "Sinatra inspired web development framework",
|
||||
"version": "3.2.4",
|
||||
"version": "3.17.6",
|
||||
"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": "Guillermo Rauch",
|
||||
"email": "rauchg@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"
|
||||
],
|
||||
"dependencies": {
|
||||
"connect": "2.7.9",
|
||||
"commander": "0.6.1",
|
||||
"range-parser": "0.0.4",
|
||||
"mkdirp": "0.3.4",
|
||||
"cookie": "0.0.5",
|
||||
"buffer-crc32": "0.2.1",
|
||||
"fresh": "0.1.0",
|
||||
"methods": "0.0.1",
|
||||
"send": "0.1.0",
|
||||
"cookie-signature": "1.0.1",
|
||||
"debug": "*"
|
||||
},
|
||||
"devDependencies": {
|
||||
"ejs": "*",
|
||||
"mocha": "*",
|
||||
"jade": "*",
|
||||
"hjs": "*",
|
||||
"stylus": "*",
|
||||
"should": "*",
|
||||
"connect-redis": "*",
|
||||
"github-flavored-markdown": "*",
|
||||
"supertest": "0.6.0"
|
||||
},
|
||||
"keywords": [
|
||||
"express",
|
||||
"framework",
|
||||
@@ -56,16 +22,52 @@
|
||||
"app",
|
||||
"api"
|
||||
],
|
||||
"repository": "git://github.com/visionmedia/express",
|
||||
"main": "index",
|
||||
"repository": "strongloop/express",
|
||||
"license": "MIT",
|
||||
"homepage": "http://expressjs.com/",
|
||||
"dependencies": {
|
||||
"basic-auth": "1.0.0",
|
||||
"connect": "2.26.4",
|
||||
"commander": "1.3.2",
|
||||
"cookie-signature": "1.0.5",
|
||||
"crc": "3.0.0",
|
||||
"debug": "~2.0.0",
|
||||
"depd": "0.4.5",
|
||||
"escape-html": "1.0.1",
|
||||
"fresh": "0.2.4",
|
||||
"media-typer": "0.3.0",
|
||||
"methods": "1.1.0",
|
||||
"mkdirp": "0.5.0",
|
||||
"parseurl": "~1.3.0",
|
||||
"proxy-addr": "~1.0.3",
|
||||
"range-parser": "~1.0.2",
|
||||
"send": "0.9.3",
|
||||
"vary": "~1.0.0",
|
||||
"cookie": "0.1.2",
|
||||
"merge-descriptors": "0.0.2"
|
||||
},
|
||||
"devDependencies": {
|
||||
"connect-redis": "~1.5.0",
|
||||
"istanbul": "0.3.2",
|
||||
"mocha": "~1.21.4",
|
||||
"should": "~4.0.0",
|
||||
"ejs": "~1.0.0",
|
||||
"jade": "~1.6.0",
|
||||
"hjs": "~0.0.6",
|
||||
"marked": "0.3.2",
|
||||
"supertest": "~0.13.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 0.8.0"
|
||||
},
|
||||
"bin": {
|
||||
"express": "./bin/express"
|
||||
},
|
||||
"scripts": {
|
||||
"prepublish": "npm prune",
|
||||
"test": "make test"
|
||||
},
|
||||
"engines": {
|
||||
"node": "*"
|
||||
"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/"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,32 +0,0 @@
|
||||
#!/usr/bin/env bash
|
||||
|
||||
NODE_ENV=production node ./support/app &
|
||||
pid=$!
|
||||
|
||||
bench() {
|
||||
ab -n 5000 -c 50 -k -q http://127.0.0.1:8000$1 \
|
||||
| grep "Requests per" \
|
||||
| cut -d ' ' -f 7 \
|
||||
| xargs echo "$2:"
|
||||
}
|
||||
|
||||
bench_conditional() {
|
||||
ab -n 5000 -c 50 -H "If-None-Match: $3" -k -q http://127.0.0.1:8000$1 \
|
||||
| grep "Requests per" \
|
||||
| cut -d ' ' -f 7 \
|
||||
| xargs echo "$2:"
|
||||
}
|
||||
|
||||
sleep .5
|
||||
bench / "Hello World"
|
||||
bench /blog "Mounted Hello World"
|
||||
bench /blog/admin "Mounted 2 Hello World"
|
||||
bench /middleware "Middleware"
|
||||
bench /match "Router"
|
||||
bench /render "Render"
|
||||
bench /json "JSON tiny"
|
||||
bench /json/15 "JSON small"
|
||||
bench /json/50 "JSON medium"
|
||||
bench /json/150 "JSON large"
|
||||
|
||||
kill -9 $pid
|
||||
@@ -1,7 +1,8 @@
|
||||
|
||||
var express = require('../')
|
||||
, Router = express.Router
|
||||
, request = require('./support/http')
|
||||
, request = require('supertest')
|
||||
, methods = require('methods')
|
||||
, assert = require('assert');
|
||||
|
||||
describe('Router', function(){
|
||||
@@ -100,4 +101,21 @@ describe('Router', function(){
|
||||
router.route('get', '/foo', function(){}, function(){});
|
||||
})
|
||||
})
|
||||
|
||||
describe('.all', function() {
|
||||
it('should support using .all to capture all http verbs', function() {
|
||||
var router = new Router();
|
||||
|
||||
router.all('/foo', function(){});
|
||||
|
||||
var url = '/foo?bar=baz';
|
||||
|
||||
methods.forEach(function testMethod(method) {
|
||||
var route = router.match(method, url);
|
||||
route.constructor.name.should.equal('Route');
|
||||
route.method.should.equal(method);
|
||||
route.path.should.equal('/foo');
|
||||
});
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
@@ -1,13 +1,5 @@
|
||||
var app = require('../../examples/auth/app')
|
||||
, request = require('../support/http');
|
||||
|
||||
function redirects(to, fn){
|
||||
return function(err, res){
|
||||
res.statusCode.should.equal(302)
|
||||
res.headers.should.have.property('location').match(to);
|
||||
fn()
|
||||
}
|
||||
}
|
||||
var request = require('supertest')
|
||||
|
||||
function getCookie(res) {
|
||||
return res.headers['set-cookie'][0].split(';')[0];
|
||||
@@ -18,25 +10,93 @@ describe('auth', function(){
|
||||
it('should redirect to /login', function(done){
|
||||
request(app)
|
||||
.get('/')
|
||||
.end(redirects(/\/login$/, done))
|
||||
.expect('Location', '/login')
|
||||
.expect(302, done)
|
||||
})
|
||||
})
|
||||
|
||||
describe('GET /restricted (w/o cookie)',function(){
|
||||
it('should redirect to /login', function(done){
|
||||
describe('GET /login',function(){
|
||||
it('should render login form', function(done){
|
||||
request(app)
|
||||
.get('/restricted')
|
||||
.end(redirects(/\/login$/,done))
|
||||
.get('/login')
|
||||
.expect(200, /<form/, done)
|
||||
})
|
||||
})
|
||||
|
||||
describe('POST /login', function(){
|
||||
it('should fail without proper credentials', function(done){
|
||||
it('should display login error', function(done){
|
||||
request(app)
|
||||
.post('/login')
|
||||
.type('urlencoded')
|
||||
.send('username=not-tj&password=foobar')
|
||||
.end(redirects(/\/login$/, done))
|
||||
.expect('Location', '/login')
|
||||
.expect(302, function(err, res){
|
||||
if (err) return done(err)
|
||||
request(app)
|
||||
.get('/login')
|
||||
.set('Cookie', getCookie(res))
|
||||
.expect(200, /Authentication failed/, done)
|
||||
})
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
describe('GET /logout',function(){
|
||||
it('should redirect to /', function(done){
|
||||
request(app)
|
||||
.get('/logout')
|
||||
.expect('Location', '/')
|
||||
.expect(302, done)
|
||||
})
|
||||
})
|
||||
|
||||
describe('GET /restricted',function(){
|
||||
it('should redirect to /login without cookie', function(done){
|
||||
request(app)
|
||||
.get('/restricted')
|
||||
.expect('Location', '/login')
|
||||
.expect(302, done)
|
||||
})
|
||||
|
||||
it('should succeed with proper cookie', function(done){
|
||||
request(app)
|
||||
.post('/login')
|
||||
.type('urlencoded')
|
||||
.send('username=tj&password=foobar')
|
||||
.expect('Location', '/')
|
||||
.expect(302, function(err, res){
|
||||
if (err) return done(err)
|
||||
request(app)
|
||||
.get('/restricted')
|
||||
.set('Cookie', getCookie(res))
|
||||
.expect(200, done)
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
describe('POST /login', function(){
|
||||
it('should fail without proper username', function(done){
|
||||
request(app)
|
||||
.post('/login')
|
||||
.type('urlencoded')
|
||||
.send('username=not-tj&password=foobar')
|
||||
.expect('Location', '/login')
|
||||
.expect(302, done)
|
||||
})
|
||||
|
||||
it('should fail without proper password', function(done){
|
||||
request(app)
|
||||
.post('/login')
|
||||
.type('urlencoded')
|
||||
.send('username=tj&password=baz')
|
||||
.expect('Location', '/login')
|
||||
.expect(302, done)
|
||||
})
|
||||
|
||||
it('should succeed with proper credentials', function(done){
|
||||
request(app)
|
||||
.post('/login')
|
||||
.type('urlencoded')
|
||||
.send('username=tj&password=foobar')
|
||||
.expect('Location', '/')
|
||||
.expect(302, done)
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
|
||||
var request = require('../support/http')
|
||||
var request = require('supertest')
|
||||
, app = require('../../examples/content-negotiation');
|
||||
|
||||
describe('content-negotiation', function(){
|
||||
@@ -7,16 +7,43 @@ describe('content-negotiation', function(){
|
||||
it('should default to text/html', function(done){
|
||||
request(app)
|
||||
.get('/')
|
||||
.expect('<ul><li>Tobi</li><li>Loki</li><li>Jane</li></ul>')
|
||||
.end(done);
|
||||
.expect(200, '<ul><li>Tobi</li><li>Loki</li><li>Jane</li></ul>', done)
|
||||
})
|
||||
|
||||
it('should accept to text/plain', function(done){
|
||||
request(app)
|
||||
.get('/')
|
||||
.set('Accept', 'text/plain')
|
||||
.expect(' - Tobi\n - Loki\n - Jane\n')
|
||||
.end(done);
|
||||
.expect(200, ' - Tobi\n - Loki\n - Jane\n', done)
|
||||
})
|
||||
|
||||
it('should accept to application/json', function(done){
|
||||
request(app)
|
||||
.get('/')
|
||||
.set('Accept', 'application/json')
|
||||
.expect(200, '[{"name":"Tobi"},{"name":"Loki"},{"name":"Jane"}]', done)
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
describe('GET /users', function(){
|
||||
it('should default to text/html', function(done){
|
||||
request(app)
|
||||
.get('/users')
|
||||
.expect(200, '<ul><li>Tobi</li><li>Loki</li><li>Jane</li></ul>', done)
|
||||
})
|
||||
|
||||
it('should accept to text/plain', function(done){
|
||||
request(app)
|
||||
.get('/users')
|
||||
.set('Accept', 'text/plain')
|
||||
.expect(200, ' - Tobi\n - Loki\n - Jane\n', done)
|
||||
})
|
||||
|
||||
it('should accept to application/json', function(done){
|
||||
request(app)
|
||||
.get('/users')
|
||||
.set('Accept', 'application/json')
|
||||
.expect(200, '[{"name":"Tobi"},{"name":"Loki"},{"name":"Jane"}]', done)
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
|
||||
var app = require('../../examples/cookies/app')
|
||||
, request = require('../support/http');
|
||||
, request = require('supertest');
|
||||
|
||||
describe('cookies', function(){
|
||||
describe('GET /', function(){
|
||||
@@ -18,6 +18,35 @@ describe('cookies', function(){
|
||||
done()
|
||||
})
|
||||
})
|
||||
|
||||
it('should respond to cookie', function(done){
|
||||
request(app)
|
||||
.post('/')
|
||||
.send({ remember: 1 })
|
||||
.expect(302, function(err, res){
|
||||
if (err) return done(err)
|
||||
request(app)
|
||||
.get('/')
|
||||
.set('Cookie', res.headers['set-cookie'][0])
|
||||
.expect(200, /Remembered/, done)
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
describe('GET /forget', function(){
|
||||
it('should clear cookie', function(done){
|
||||
request(app)
|
||||
.post('/')
|
||||
.send({ remember: 1 })
|
||||
.expect(302, function(err, res){
|
||||
if (err) return done(err)
|
||||
request(app)
|
||||
.get('/forget')
|
||||
.set('Cookie', res.headers['set-cookie'][0])
|
||||
.expect('Set-Cookie', /remember=;/)
|
||||
.expect(302, done)
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
describe('POST /', function(){
|
||||
@@ -25,10 +54,20 @@ describe('cookies', function(){
|
||||
request(app)
|
||||
.post('/')
|
||||
.send({ remember: 1 })
|
||||
.end(function(err, res){
|
||||
.expect(302, function(err, res){
|
||||
res.headers.should.have.property('set-cookie')
|
||||
done()
|
||||
})
|
||||
})
|
||||
|
||||
it('should no set cookie w/o reminder', function(done){
|
||||
request(app)
|
||||
.post('/')
|
||||
.send({})
|
||||
.expect(302, function(err, res){
|
||||
res.headers.should.not.have.property('set-cookie')
|
||||
done()
|
||||
})
|
||||
})
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
|
||||
var app = require('../../examples/downloads/app')
|
||||
, request = require('../support/http');
|
||||
, request = require('supertest');
|
||||
|
||||
describe('downloads', function(){
|
||||
describe('GET /', function(){
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
|
||||
var request = require('../support/http')
|
||||
var request = require('supertest')
|
||||
, app = require('../../examples/ejs');
|
||||
|
||||
describe('ejs', function(){
|
||||
@@ -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/error-pages')
|
||||
, request = require('../support/http');
|
||||
, request = require('supertest');
|
||||
|
||||
describe('error-pages', function(){
|
||||
describe('GET /', function(){
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
|
||||
var app = require('../../examples/error')
|
||||
, request = require('../support/http');
|
||||
, request = require('supertest');
|
||||
|
||||
describe('error', function(){
|
||||
describe('GET /', function(){
|
||||
|
||||
@@ -1,13 +1,13 @@
|
||||
|
||||
var app = require('../../examples/markdown')
|
||||
, request = require('../support/http');
|
||||
var request = require('supertest')
|
||||
|
||||
describe('markdown', function(){
|
||||
describe('GET /', function(){
|
||||
it('should respond with html', function(done){
|
||||
request(app)
|
||||
.get('/')
|
||||
.expect(/<h1>Markdown Example<\/h1>/,done)
|
||||
.expect(/<h1[^>]*>Markdown Example<\/h1>/,done)
|
||||
})
|
||||
})
|
||||
|
||||
@@ -18,4 +18,4 @@ describe('markdown', function(){
|
||||
.expect(500,done)
|
||||
})
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
|
||||
var request = require('../support/http')
|
||||
var request = require('supertest')
|
||||
, app = require('../../examples/mvc');
|
||||
|
||||
describe('mvc', function(){
|
||||
@@ -7,10 +7,39 @@ describe('mvc', function(){
|
||||
it('should redirect to /users', function(done){
|
||||
request(app)
|
||||
.get('/')
|
||||
.expect('Location', '/users')
|
||||
.expect(302, done)
|
||||
})
|
||||
})
|
||||
|
||||
describe('GET /pet/0', function(){
|
||||
it('should get pet', function(done){
|
||||
request(app)
|
||||
.get('/pet/0')
|
||||
.expect(200, /Tobi/, done)
|
||||
})
|
||||
})
|
||||
|
||||
describe('GET /pet/0/edit', function(){
|
||||
it('should get pet edit page', function(done){
|
||||
request(app)
|
||||
.get('/pet/0/edit')
|
||||
.expect(/<form/)
|
||||
.expect(200, /Tobi/, done)
|
||||
})
|
||||
})
|
||||
|
||||
describe('PUT /pet/2', 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){
|
||||
res.should.have.status(302);
|
||||
res.headers.location.should.include('/users');
|
||||
done();
|
||||
if (err) return done(err);
|
||||
request(app)
|
||||
.get('/pet/3/edit')
|
||||
.expect(200, /Boots/, done)
|
||||
})
|
||||
})
|
||||
})
|
||||
@@ -19,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)
|
||||
})
|
||||
})
|
||||
|
||||
@@ -34,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)
|
||||
})
|
||||
})
|
||||
|
||||
@@ -65,11 +87,8 @@ describe('mvc', function(){
|
||||
it('should display the edit form', function(done){
|
||||
request(app)
|
||||
.get('/user/1/edit')
|
||||
.end(function(err, res){
|
||||
res.text.should.include('<h1>Guillermo</h1>');
|
||||
res.text.should.include('value="put"');
|
||||
done();
|
||||
})
|
||||
.expect(/Guillermo/)
|
||||
.expect(200, /<form/, done)
|
||||
})
|
||||
})
|
||||
|
||||
@@ -77,15 +96,30 @@ 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);
|
||||
request(app)
|
||||
.get('/user/1/edit')
|
||||
.end(function(err, res){
|
||||
res.text.should.include('<h1>Tobo</h1>');
|
||||
done();
|
||||
})
|
||||
.expect(200, /Tobo/, done)
|
||||
})
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
describe('POST /user/:id/pet', 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){
|
||||
if (err) return done(err)
|
||||
request(app)
|
||||
.get('/user/2')
|
||||
.expect(200, /Snickers/, done)
|
||||
})
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
var app = require('../../examples/params/app')
|
||||
, request = require('../support/http');
|
||||
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('../support/http');
|
||||
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)
|
||||
})
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
|
||||
var request = require('../support/http')
|
||||
var request = require('supertest')
|
||||
, app = require('../../examples/web-service');
|
||||
|
||||
describe('web-service', function(){
|
||||
@@ -24,11 +24,72 @@ describe('web-service', function(){
|
||||
it('should respond users json', function(done){
|
||||
request(app)
|
||||
.get('/api/users?api-key=foo')
|
||||
.end(function(err, res){
|
||||
res.should.be.json;
|
||||
res.text.should.equal('[{"name":"tobi"},{"name":"loki"},{"name":"jane"}]');
|
||||
done();
|
||||
});
|
||||
.expect('Content-Type', 'application/json; charset=utf-8')
|
||||
.expect(200, '[{"name":"tobi"},{"name":"loki"},{"name":"jane"}]', done)
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
describe('GET /api/repos', function(){
|
||||
describe('without an api key', function(){
|
||||
it('should respond with 400 bad request', function(done){
|
||||
request(app)
|
||||
.get('/api/repos')
|
||||
.expect(400, done);
|
||||
})
|
||||
})
|
||||
|
||||
describe('with an invalid api key', function(){
|
||||
it('should respond with 401 unauthorized', function(done){
|
||||
request(app)
|
||||
.get('/api/repos?api-key=rawr')
|
||||
.expect(401, done);
|
||||
})
|
||||
})
|
||||
|
||||
describe('with a valid api key', function(){
|
||||
it('should respond repos json', function(done){
|
||||
request(app)
|
||||
.get('/api/repos?api-key=foo')
|
||||
.expect('Content-Type', 'application/json; charset=utf-8')
|
||||
.expect(/"name":"express"/)
|
||||
.expect(/"url":"http:\/\/github.com\/strongloop\/express"/)
|
||||
.expect(200, done)
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
describe('GET /api/user/:name/repos', function(){
|
||||
describe('without an api key', function(){
|
||||
it('should respond with 400 bad request', function(done){
|
||||
request(app)
|
||||
.get('/api/user/loki/repos')
|
||||
.expect(400, done);
|
||||
})
|
||||
})
|
||||
|
||||
describe('with an invalid api key', function(){
|
||||
it('should respond with 401 unauthorized', function(done){
|
||||
request(app)
|
||||
.get('/api/user/loki/repos?api-key=rawr')
|
||||
.expect(401, done);
|
||||
})
|
||||
})
|
||||
|
||||
describe('with a valid api key', function(){
|
||||
it('should respond user repos json', function(done){
|
||||
request(app)
|
||||
.get('/api/user/loki/repos?api-key=foo')
|
||||
.expect('Content-Type', 'application/json; charset=utf-8')
|
||||
.expect(/"name":"stylus"/)
|
||||
.expect(/"url":"http:\/\/github.com\/learnboost\/stylus"/)
|
||||
.expect(200, done)
|
||||
})
|
||||
|
||||
it('should 404 with unknown user', function(done){
|
||||
request(app)
|
||||
.get('/api/user/bob/repos?api-key=foo')
|
||||
.expect(404, done)
|
||||
})
|
||||
})
|
||||
})
|
||||
@@ -37,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)
|
||||
})
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
|
||||
var express = require('../')
|
||||
, request = require('./support/http');
|
||||
, request = require('supertest');
|
||||
|
||||
describe('app.all()', function(){
|
||||
it('should add a router per method', function(done){
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
|
||||
var express = require('../')
|
||||
, request = require('./support/http');
|
||||
, request = require('supertest');
|
||||
|
||||
describe('app.del()', function(){
|
||||
it('should alias app.delete()', function(done){
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
|
||||
var express = require('../')
|
||||
, request = require('./support/http')
|
||||
, assert = require('assert');
|
||||
var express = require('../');
|
||||
var request = require('supertest');
|
||||
var assert = require('assert');
|
||||
|
||||
describe('HEAD', function(){
|
||||
it('should default to GET', function(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(){
|
||||
|
||||
11
test/app.js
11
test/app.js
@@ -71,4 +71,13 @@ describe('in production', function(){
|
||||
app.enabled('view cache').should.be.true;
|
||||
process.env.NODE_ENV = 'test';
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
describe('without NODE_ENV', function(){
|
||||
it('should default to development', function(){
|
||||
process.env.NODE_ENV = '';
|
||||
var app = express();
|
||||
app.get('env').should.equal('development');
|
||||
process.env.NODE_ENV = 'test';
|
||||
})
|
||||
})
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
|
||||
var express = require('../')
|
||||
, request = require('./support/http');
|
||||
, request = require('supertest');
|
||||
|
||||
describe('app.listen()', function(){
|
||||
it('should wrap with an HTTP server', function(done){
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
|
||||
var express = require('../')
|
||||
, request = require('./support/http');
|
||||
, request = require('supertest');
|
||||
|
||||
describe('app', function(){
|
||||
describe('.locals(obj)', function(){
|
||||
@@ -14,7 +14,7 @@ describe('app', function(){
|
||||
app.locals.age.should.equal(2);
|
||||
})
|
||||
})
|
||||
|
||||
|
||||
describe('.locals.settings', function(){
|
||||
it('should expose app settings', function(){
|
||||
var app = express();
|
||||
|
||||
61
test/app.options.js
Normal file
61
test/app.options.js
Normal file
@@ -0,0 +1,61 @@
|
||||
|
||||
var express = require('../')
|
||||
, request = require('supertest');
|
||||
|
||||
describe('OPTIONS', function(){
|
||||
it('should default to the routes defined', function(done){
|
||||
var app = express();
|
||||
|
||||
app.del('/', function(){});
|
||||
app.get('/users', function(req, res){});
|
||||
app.put('/users', function(req, res){});
|
||||
|
||||
request(app)
|
||||
.options('/users')
|
||||
.expect('GET,PUT')
|
||||
.expect('Allow', 'GET,PUT', done);
|
||||
})
|
||||
|
||||
it('should not respond if the path is not defined', function(done){
|
||||
var app = express();
|
||||
|
||||
app.get('/users', function(req, res){});
|
||||
|
||||
request(app)
|
||||
.options('/other')
|
||||
.expect(404, done);
|
||||
})
|
||||
|
||||
it('should forward requests down the middleware chain', function(done){
|
||||
var app = express();
|
||||
var router = new express.Router();
|
||||
|
||||
router.get('/users', function(req, res){});
|
||||
app.use(router.middleware);
|
||||
app.get('/other', function(req, res){});
|
||||
|
||||
request(app)
|
||||
.options('/other')
|
||||
.expect('GET')
|
||||
.expect('Allow', 'GET', done);
|
||||
})
|
||||
})
|
||||
|
||||
describe('app.options()', function(){
|
||||
it('should override the default behavior', function(done){
|
||||
var app = express();
|
||||
|
||||
app.options('/users', function(req, res){
|
||||
res.set('Allow', 'GET');
|
||||
res.send('GET');
|
||||
});
|
||||
|
||||
app.get('/users', function(req, res){});
|
||||
app.put('/users', function(req, res){});
|
||||
|
||||
request(app)
|
||||
.options('/users')
|
||||
.expect('GET')
|
||||
.expect('Allow', 'GET', done);
|
||||
})
|
||||
})
|
||||
@@ -1,6 +1,6 @@
|
||||
|
||||
var express = require('../')
|
||||
, request = require('./support/http');
|
||||
, request = require('supertest');
|
||||
|
||||
describe('app', function(){
|
||||
describe('.param(fn)', function(){
|
||||
@@ -37,6 +37,11 @@ describe('app', function(){
|
||||
});
|
||||
|
||||
})
|
||||
|
||||
it('should fail if not given fn', function(){
|
||||
var app = express();
|
||||
app.param.bind(app, ':name', 'bob').should.throw();
|
||||
})
|
||||
})
|
||||
|
||||
describe('.param(names, fn)', function(){
|
||||
@@ -52,13 +57,13 @@ describe('app', function(){
|
||||
|
||||
app.get('/post/:id', function(req, res){
|
||||
var id = req.params.id;
|
||||
id.should.be.a('number');
|
||||
id.should.be.a.Number;
|
||||
res.send('' + id);
|
||||
});
|
||||
|
||||
app.get('/user/:uid', function(req, res){
|
||||
var id = req.params.id;
|
||||
id.should.be.a('number');
|
||||
id.should.be.a.Number;
|
||||
res.send('' + id);
|
||||
});
|
||||
|
||||
@@ -87,7 +92,7 @@ describe('app', function(){
|
||||
|
||||
app.get('/user/:id', function(req, res){
|
||||
var id = req.params.id;
|
||||
id.should.be.a('number');
|
||||
id.should.be.a.Number;
|
||||
res.send('' + id);
|
||||
});
|
||||
|
||||
@@ -95,5 +100,61 @@ describe('app', function(){
|
||||
.get('/user/123')
|
||||
.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();
|
||||
|
||||
app.param('id', function(req, res, next, id){
|
||||
throw new Error('err!');
|
||||
});
|
||||
|
||||
app.get('/user/:id', function(req, res){
|
||||
var id = req.params.id;
|
||||
res.send('' + id);
|
||||
});
|
||||
|
||||
request(app)
|
||||
.get('/user/123')
|
||||
.expect(500, done);
|
||||
})
|
||||
|
||||
it('should defer to next route', function(done){
|
||||
var app = express();
|
||||
|
||||
app.param('id', function(req, res, next, id){
|
||||
next('route');
|
||||
});
|
||||
|
||||
app.get('/user/:id', function(req, res){
|
||||
var id = req.params.id;
|
||||
res.send('' + id);
|
||||
});
|
||||
|
||||
app.get('/:name/123', function(req, res){
|
||||
res.send('name');
|
||||
});
|
||||
|
||||
request(app)
|
||||
.get('/user/123')
|
||||
.expect('name', done);
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
@@ -54,12 +54,33 @@ describe('app', function(){
|
||||
})
|
||||
})
|
||||
|
||||
it('should handle render error throws', function(done){
|
||||
var app = express();
|
||||
|
||||
function View(name, options){
|
||||
this.name = name;
|
||||
this.path = 'fale';
|
||||
}
|
||||
|
||||
View.prototype.render = function(options, fn){
|
||||
throw new Error('err!');
|
||||
};
|
||||
|
||||
app.set('view', View);
|
||||
|
||||
app.render('something', function(err, str){
|
||||
err.should.be.ok;
|
||||
err.message.should.equal('err!');
|
||||
done();
|
||||
})
|
||||
})
|
||||
|
||||
describe('when the file does not exist', function(){
|
||||
it('should provide a helpful error', function(done){
|
||||
var app = express();
|
||||
app.set('views', __dirname + '/fixtures');
|
||||
app.render('rawr.jade', function(err){
|
||||
err.message.should.equal('Failed to lookup view "rawr.jade"');
|
||||
err.message.should.equal('Failed to lookup view "rawr.jade" in views directory "' + __dirname + '/fixtures"');
|
||||
done();
|
||||
});
|
||||
})
|
||||
@@ -74,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();
|
||||
});
|
||||
})
|
||||
@@ -132,6 +153,68 @@ describe('app', function(){
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
describe('caching', function(){
|
||||
it('should always lookup view without cache', function(done){
|
||||
var app = express();
|
||||
var count = 0;
|
||||
|
||||
function View(name, options){
|
||||
this.name = name;
|
||||
this.path = 'fake';
|
||||
count++;
|
||||
}
|
||||
|
||||
View.prototype.render = function(options, fn){
|
||||
fn(null, 'abstract engine');
|
||||
};
|
||||
|
||||
app.set('view cache', false);
|
||||
app.set('view', View);
|
||||
|
||||
app.render('something', function(err, str){
|
||||
if (err) return done(err);
|
||||
count.should.equal(1);
|
||||
str.should.equal('abstract engine');
|
||||
app.render('something', function(err, str){
|
||||
if (err) return done(err);
|
||||
count.should.equal(2);
|
||||
str.should.equal('abstract engine');
|
||||
done();
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
it('should cache with "view cache" setting', function(done){
|
||||
var app = express();
|
||||
var count = 0;
|
||||
|
||||
function View(name, options){
|
||||
this.name = name;
|
||||
this.path = 'fake';
|
||||
count++;
|
||||
}
|
||||
|
||||
View.prototype.render = function(options, fn){
|
||||
fn(null, 'abstract engine');
|
||||
};
|
||||
|
||||
app.set('view cache', true);
|
||||
app.set('view', View);
|
||||
|
||||
app.render('something', function(err, str){
|
||||
if (err) return done(err);
|
||||
count.should.equal(1);
|
||||
str.should.equal('abstract engine');
|
||||
app.render('something', function(err, str){
|
||||
if (err) return done(err);
|
||||
count.should.equal(1);
|
||||
str.should.equal('abstract engine');
|
||||
done();
|
||||
})
|
||||
})
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
describe('.render(name, options, fn)', function(){
|
||||
@@ -175,5 +258,37 @@ describe('app', function(){
|
||||
done();
|
||||
})
|
||||
})
|
||||
|
||||
describe('caching', function(){
|
||||
it('should cache with cache option', function(done){
|
||||
var app = express();
|
||||
var count = 0;
|
||||
|
||||
function View(name, options){
|
||||
this.name = name;
|
||||
this.path = 'fake';
|
||||
count++;
|
||||
}
|
||||
|
||||
View.prototype.render = function(options, fn){
|
||||
fn(null, 'abstract engine');
|
||||
};
|
||||
|
||||
app.set('view cache', false);
|
||||
app.set('view', View);
|
||||
|
||||
app.render('something', {cache: true}, function(err, str){
|
||||
if (err) return done(err);
|
||||
count.should.equal(1);
|
||||
str.should.equal('abstract engine');
|
||||
app.render('something', {cache: true}, function(err, str){
|
||||
if (err) return done(err);
|
||||
count.should.equal(1);
|
||||
str.should.equal('abstract engine');
|
||||
done();
|
||||
})
|
||||
})
|
||||
})
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
|
||||
var express = require('../')
|
||||
, request = require('./support/http');
|
||||
, request = require('supertest');
|
||||
|
||||
describe('app', function(){
|
||||
describe('.request', function(){
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
|
||||
var express = require('../')
|
||||
, request = require('./support/http');
|
||||
, request = require('supertest');
|
||||
|
||||
describe('app', function(){
|
||||
describe('.response', function(){
|
||||
@@ -19,7 +19,7 @@ describe('app', function(){
|
||||
.get('/')
|
||||
.expect('HEY', done);
|
||||
})
|
||||
|
||||
|
||||
it('should not be influenced by other app protos', function(done){
|
||||
var app = express()
|
||||
, app2 = express();
|
||||
@@ -27,7 +27,7 @@ describe('app', function(){
|
||||
app.response.shout = function(str){
|
||||
this.send(str.toUpperCase());
|
||||
};
|
||||
|
||||
|
||||
app2.response.shout = function(str){
|
||||
this.send(str);
|
||||
};
|
||||
|
||||
@@ -1,14 +1,15 @@
|
||||
|
||||
var express = require('../')
|
||||
, request = require('./support/http')
|
||||
, request = require('supertest')
|
||||
, assert = require('assert')
|
||||
, methods = require('methods');
|
||||
|
||||
describe('app.router', function(){
|
||||
describe('methods supported', function(){
|
||||
methods.forEach(function(method){
|
||||
methods.concat('del').forEach(function(method){
|
||||
if (method === 'connect') return;
|
||||
|
||||
it('should include ' + method.toUpperCase(), function(done){
|
||||
if (method == 'delete') method = 'del';
|
||||
var app = express();
|
||||
var calls = [];
|
||||
|
||||
@@ -27,16 +28,54 @@ describe('app.router', function(){
|
||||
});
|
||||
})
|
||||
|
||||
it('should decode params', function(done){
|
||||
var app = express();
|
||||
describe('decode querystring', function(){
|
||||
it('should decode correct params', function(done){
|
||||
var app = express();
|
||||
|
||||
app.get('/:name', function(req, res, next){
|
||||
res.send(req.params.name);
|
||||
});
|
||||
app.get('/:name', function(req, res, next){
|
||||
res.send(req.params.name);
|
||||
});
|
||||
|
||||
request(app)
|
||||
.get('/foo%2Fbar')
|
||||
.expect('foo/bar', done);
|
||||
request(app)
|
||||
.get('/foo%2Fbar')
|
||||
.expect('foo/bar', done);
|
||||
})
|
||||
|
||||
it('should not accept params in malformed paths', function(done) {
|
||||
var app = express();
|
||||
|
||||
app.get('/:name', function(req, res, next){
|
||||
res.send(req.params.name);
|
||||
});
|
||||
|
||||
request(app)
|
||||
.get('/%foobar')
|
||||
.expect(400, done);
|
||||
})
|
||||
|
||||
it('should not decode spaces', function(done) {
|
||||
var app = express();
|
||||
|
||||
app.get('/:name', function(req, res, next){
|
||||
res.send(req.params.name);
|
||||
});
|
||||
|
||||
request(app)
|
||||
.get('/foo+bar')
|
||||
.expect('foo+bar', done);
|
||||
})
|
||||
|
||||
it('should work with unicode', function(done) {
|
||||
var app = express();
|
||||
|
||||
app.get('/:name', function(req, res, next){
|
||||
res.send(req.params.name);
|
||||
});
|
||||
|
||||
request(app)
|
||||
.get('/%ce%b1')
|
||||
.expect('\u03b1', done);
|
||||
})
|
||||
})
|
||||
|
||||
it('should be .use()able', function(done){
|
||||
@@ -114,8 +153,8 @@ describe('app.router', function(){
|
||||
var app = express();
|
||||
|
||||
app.get(/^\/user\/([0-9]+)\/(view|edit)?$/, function(req, res){
|
||||
var id = req.params.shift()
|
||||
, op = req.params.shift();
|
||||
var id = req.params[0]
|
||||
, op = req.params[1];
|
||||
res.end(op + 'ing user ' + id);
|
||||
});
|
||||
|
||||
@@ -290,8 +329,8 @@ describe('app.router', function(){
|
||||
var app = express();
|
||||
|
||||
app.get('/api/*.*', function(req, res){
|
||||
var resource = req.params.shift()
|
||||
, format = req.params.shift();
|
||||
var resource = req.params[0]
|
||||
, format = req.params[1];
|
||||
res.end(resource + ' as ' + format);
|
||||
});
|
||||
|
||||
@@ -525,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()
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
var express = require('../')
|
||||
, request = require('./support/http');
|
||||
, request = require('supertest');
|
||||
|
||||
describe('app', function(){
|
||||
describe('.VERB()', function(){
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
|
||||
var express = require('../')
|
||||
, assert = require('assert')
|
||||
, request = require('./support/http');
|
||||
, request = require('supertest');
|
||||
|
||||
describe('app.routes', function(){
|
||||
it('should be initialized', function(){
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
|
||||
var express = require('../')
|
||||
, request = require('./support/http');
|
||||
, request = require('supertest');
|
||||
|
||||
describe('app', function(){
|
||||
it('should emit "mount" when mounted', function(done){
|
||||
@@ -23,7 +23,7 @@ describe('app', function(){
|
||||
blog.get('/blog', function(req, res){
|
||||
res.end('blog');
|
||||
});
|
||||
|
||||
|
||||
app.use(blog);
|
||||
|
||||
request(app)
|
||||
|
||||
@@ -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,13 +1,9 @@
|
||||
|
||||
var express = require('../')
|
||||
, request = require('./support/http')
|
||||
, assert = require('assert');
|
||||
var express = require('../');
|
||||
var request = require('supertest');
|
||||
var assert = require('assert');
|
||||
|
||||
describe('exports', function(){
|
||||
it('should have .version', function(){
|
||||
express.should.have.property('version');
|
||||
})
|
||||
|
||||
it('should expose connect middleware', function(){
|
||||
express.should.have.property('bodyParser');
|
||||
express.should.have.property('session');
|
||||
@@ -19,19 +15,19 @@ describe('exports', function(){
|
||||
})
|
||||
|
||||
it('should expose Router', function(){
|
||||
express.Router.should.be.a('function');
|
||||
express.Router.should.be.a.Function;
|
||||
})
|
||||
|
||||
|
||||
it('should expose the application prototype', function(){
|
||||
express.application.set.should.be.a('function');
|
||||
express.application.set.should.be.a.Function;
|
||||
})
|
||||
|
||||
|
||||
it('should expose the request prototype', function(){
|
||||
express.request.accepts.should.be.a('function');
|
||||
express.request.accepts.should.be.a.Function;
|
||||
})
|
||||
|
||||
|
||||
it('should expose the response prototype', function(){
|
||||
express.response.send.should.be.a('function');
|
||||
express.response.send.should.be.a.Function;
|
||||
})
|
||||
|
||||
it('should permit modifying the .application prototype', function(){
|
||||
@@ -51,7 +47,7 @@ describe('exports', function(){
|
||||
.get('/')
|
||||
.expect('bar', done);
|
||||
})
|
||||
|
||||
|
||||
it('should permit modifying the .response prototype', function(done){
|
||||
express.response.foo = function(){ this.send('bar'); };
|
||||
var app = express();
|
||||
|
||||
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>
|
||||
@@ -1,6 +1,6 @@
|
||||
//
|
||||
// var express = require('../')
|
||||
// , request = require('./support/http');
|
||||
// , request = require('supertest');
|
||||
//
|
||||
// describe('middleware', function(){
|
||||
// describe('.next()', function(){
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
|
||||
var express = require('../')
|
||||
, request = require('./support/http');
|
||||
, request = require('supertest');
|
||||
|
||||
describe('throw after .end()', function(){
|
||||
it('should fail gracefully', function(done){
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
|
||||
var express = require('../')
|
||||
, request = require('./support/http');
|
||||
, request = require('supertest');
|
||||
|
||||
describe('req', function(){
|
||||
describe('.accepted', function(){
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
|
||||
var express = require('../')
|
||||
, request = require('./support/http');
|
||||
, request = require('supertest');
|
||||
|
||||
describe('req', function(){
|
||||
describe('.acceptedCharsets', function(){
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
|
||||
var express = require('../')
|
||||
, request = require('./support/http');
|
||||
, request = require('supertest');
|
||||
|
||||
describe('req', function(){
|
||||
describe('.acceptedEncodings', function(){
|
||||
@@ -29,6 +29,7 @@ describe('req', function(){
|
||||
|
||||
request(app)
|
||||
.get('/')
|
||||
.set('Accept-Encoding', '')
|
||||
.expect(200, done);
|
||||
})
|
||||
})
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
|
||||
var express = require('../')
|
||||
, request = require('./support/http');
|
||||
, request = require('supertest');
|
||||
|
||||
describe('req', function(){
|
||||
describe('.acceptedLanguages', function(){
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
|
||||
var express = require('../')
|
||||
, request = require('./support/http');
|
||||
, request = require('supertest');
|
||||
|
||||
describe('req', function(){
|
||||
describe('.accepts(type)', function(){
|
||||
@@ -56,7 +56,20 @@ describe('req', function(){
|
||||
.expect('html', done);
|
||||
})
|
||||
|
||||
describe('.accept(types)', function(){
|
||||
it('should accept an argument list of type names', function(done){
|
||||
var app = express();
|
||||
|
||||
app.use(function(req, res, next){
|
||||
res.end(req.accepts('json', 'html'));
|
||||
});
|
||||
|
||||
request(app)
|
||||
.get('/')
|
||||
.set('Accept', 'application/json')
|
||||
.expect('json', done);
|
||||
})
|
||||
|
||||
describe('.accepts(types)', function(){
|
||||
it('should return the first when Accept is not present', function(done){
|
||||
var app = express();
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
|
||||
var express = require('../')
|
||||
, request = require('./support/http');
|
||||
, request = require('supertest');
|
||||
|
||||
describe('req', function(){
|
||||
describe('.acceptsCharset(type)', function(){
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user