Compare commits

...

696 Commits

Author SHA1 Message Date
Douglas Christopher Wilson
b78bd3d1fd 4.10.6 2014-12-12 23:13:34 -05:00
Douglas Christopher Wilson
4aa2801054 Merge tag '3.18.6' 2014-12-12 22:06:21 -05:00
Douglas Christopher Wilson
4405b849a9 3.18.6 2014-12-12 21:39:47 -05:00
Troy Goode
5d74a553d6 Fix exception in req.fresh/req.stale without response headers
fixes #2468
2014-12-12 21:17:23 -05:00
Douglas Christopher Wilson
262b60537f 3.18.5 2014-12-11 23:10:34 -05:00
Douglas Christopher Wilson
e77e644224 deps: should@~4.3.1 2014-12-11 23:03:01 -05:00
Douglas Christopher Wilson
ce89c00cd9 deps: istanbul@0.3.5 2014-12-11 23:01:12 -05:00
Douglas Christopher Wilson
4d8093302f 4.10.5 2014-12-10 23:53:31 -05:00
Douglas Christopher Wilson
4370908674 deps: type-is@~1.5.4 2014-12-10 23:50:58 -05:00
Douglas Christopher Wilson
f0b679d02d deps: accepts@~1.1.4 2014-12-10 23:49:34 -05:00
Douglas Christopher Wilson
d5ad34b0e9 deps: connect@2.27.6 2014-12-10 22:55:36 -05:00
Douglas Christopher Wilson
c24463d829 Fix res.send double-calling res.end for HEAD requests
fixes #2467
2014-12-10 12:27:08 -05:00
Douglas Christopher Wilson
ebfa00a9c0 build: remove support folder 2014-11-29 12:10:30 -05:00
Douglas Christopher Wilson
d23417e6e8 examples: switch examples used in tests to ejs engine 2014-11-29 12:09:00 -05:00
Douglas Christopher Wilson
91824514ce tests: run render tests with internal template engine 2014-11-28 09:10:44 -05:00
Douglas Christopher Wilson
656e214937 4.10.4 2014-11-25 00:17:24 -05:00
Douglas Christopher Wilson
4b26bbde2d Fix res.sendFile logging standard write errors
closes #2451
2014-11-24 23:28:37 -05:00
Douglas Christopher Wilson
7fcc8b190d 4.10.3 2014-11-23 18:48:55 -05:00
Douglas Christopher Wilson
b326ae89df Fix res.sendFile logging standard write errors
fixes #2433
2014-11-23 16:53:11 -05:00
Douglas Christopher Wilson
869ddd775c deps: update example dependencies 2014-11-23 15:58:24 -05:00
Douglas Christopher Wilson
997fd74e8c deps: qs@2.3.3 2014-11-23 15:56:59 -05:00
Douglas Christopher Wilson
e3e41a1118 Merge tag '3.18.4' 2014-11-23 15:54:20 -05:00
Douglas Christopher Wilson
6c8bcd5c4e 3.18.4 2014-11-23 15:42:03 -05:00
Douglas Christopher Wilson
95e63ec287 deps: should@~4.3.0 2014-11-23 15:36:59 -05:00
Douglas Christopher Wilson
ebca5887cc deps: proxy-addr@~1.0.4 2014-11-23 15:34:57 -05:00
Douglas Christopher Wilson
8535d3a990 deps: supertest@~0.15.0 2014-11-23 14:58:56 -05:00
Douglas Christopher Wilson
13184c4379 deps: etag@~1.5.1 2014-11-23 14:58:22 -05:00
Douglas Christopher Wilson
eaba4eeb70 deps: connect@2.27.4 2014-11-23 14:53:23 -05:00
Douglas Christopher Wilson
ac56cf4606 4.10.2 2014-11-09 19:09:24 -05:00
Josemar Magalhaes
6dea32cd18 examples: add multi router example
closes #2434
2014-11-09 19:01:13 -05:00
Douglas Christopher Wilson
5fab60bc6c Correctly invoke async router callback asynchronously 2014-11-09 18:50:00 -05:00
Douglas Christopher Wilson
881e1ba660 deps: type-is@~1.5.3 2014-11-09 18:42:33 -05:00
Douglas Christopher Wilson
0e488c19df deps: accepts@~1.1.3 2014-11-09 18:41:01 -05:00
Douglas Christopher Wilson
2262a18900 Merge tag '3.18.3' 2014-11-09 18:39:46 -05:00
Douglas Christopher Wilson
28c6952d1c 3.18.3 2014-11-09 18:35:34 -05:00
Douglas Christopher Wilson
01e3530a31 deps: should@~4.2.1 2014-11-09 18:33:17 -05:00
Douglas Christopher Wilson
77c83d0c57 deps: connect@2.27.3 2014-11-09 18:32:43 -05:00
Douglas Christopher Wilson
b4eaf89186 examples: remove invalid cors example
Not only is the example not even standards-compliant, but it
encourages bad security settings and practices.
2014-11-06 21:14:02 -05:00
Douglas Christopher Wilson
e4debea297 Remove unused source file 2014-11-01 14:09:12 -04:00
Jaime Agudo
1c96e18d20 docs: fix Gratipay links
fixes #2424
2014-11-01 00:09:54 -04:00
Douglas Christopher Wilson
8bb013ec95 4.10.1 2014-10-29 01:15:58 -04:00
Douglas Christopher Wilson
6c0031bfd8 deps: qs@2.3.2 2014-10-29 01:14:44 -04:00
Douglas Christopher Wilson
ab6c189504 Merge tag '3.18.2' 2014-10-29 01:14:04 -04:00
Douglas Christopher Wilson
a12ae729bd 3.18.2 2014-10-29 01:10:45 -04:00
Douglas Christopher Wilson
d53a0cd91e deps: connect@2.27.2 2014-10-29 01:08:36 -04:00
Aria Stewart
eabd4564aa Fix handling of URLs containing :// in the path
fixes #2421
2014-10-29 00:33:02 -04:00
Douglas Christopher Wilson
d40dc651f3 4.10.0 2014-10-23 22:27:45 -04:00
Douglas Christopher Wilson
68290ee87a Fix handling of invalid empty URLs
fixes #2399
2014-10-23 21:33:38 -04:00
Douglas Christopher Wilson
6614352563 Add support for app.set('views', array)
closes #2320
2014-10-23 17:28:53 -04:00
Douglas Christopher Wilson
0e5f2f84ea Use path.resolve in view lookup 2014-10-23 15:55:17 -04:00
Douglas Christopher Wilson
b1d0c19ca1 examples: make main app file names consistent
fixes #2408
2014-10-23 02:39:38 -04:00
lemmy
dfa7ee4732 Pass context to .forEach instead of closure
Has a slight performance improvement

closes #2347
2014-10-23 02:30:09 -04:00
Douglas Christopher Wilson
e9539fc780 docs: visionmedia is now tj on Github 2014-10-23 02:20:51 -04:00
Fishrock123
5f7a37ee51 docs: misc. tweaks
closes #2394
2014-10-23 02:18:24 -04:00
Douglas Christopher Wilson
ff3a368b2f deps: update example dependencies 2014-10-23 02:08:34 -04:00
Douglas Christopher Wilson
ccc45a74f8 Merge tag '3.18.1' 2014-10-23 02:06:20 -04:00
Douglas Christopher Wilson
cd9d2ec6a9 deps: on-finished@~2.1.1 2014-10-23 01:45:58 -04:00
Douglas Christopher Wilson
ce7bbae007 deps: serve-static@~1.7.1 2014-10-23 01:43:19 -04:00
Douglas Christopher Wilson
6a5dd52deb deps: qs@2.3.0 2014-10-23 01:38:48 -04:00
Douglas Christopher Wilson
6c2f7fb48d deps: finalhandler@0.3.2 2014-10-23 01:37:00 -04:00
Douglas Christopher Wilson
4dd970578a Fix res.send to mention res.sendStatus 2014-10-23 01:35:16 -04:00
Douglas Christopher Wilson
88dfd36eaa 3.18.1 2014-10-23 01:26:21 -04:00
Douglas Christopher Wilson
5759b3e9f5 deps: send@0.10.1 2014-10-23 01:25:07 -04:00
Douglas Christopher Wilson
c939a771c0 deps: connect@2.27.1 2014-10-23 01:23:54 -04:00
Douglas Christopher Wilson
af1043844f Fix internal utils.merge deprecation warnings 2014-10-22 15:18:10 -04:00
Douglas Christopher Wilson
dd763ec5b8 deps: should@~4.1.0 2014-10-22 15:10:22 -04:00
Douglas Christopher Wilson
9c2c21aaaf deps: mocha@~2.0.0 2014-10-22 15:08:49 -04:00
Douglas Christopher Wilson
366000184f 3.18.0 2014-10-18 00:57:48 -04:00
Douglas Christopher Wilson
4d1ee23f84 Use etag module to generate ETag headers 2014-10-18 00:53:17 -04:00
Douglas Christopher Wilson
6f31218ecc Use content-disposition module 2014-10-17 23:45:58 -04:00
Douglas Christopher Wilson
6cd4859035 deps: finalhandler@0.3.1 2014-10-17 22:37:52 -04:00
Douglas Christopher Wilson
4f1cd4f73c deps: etag@~1.5.0 2014-10-17 22:37:49 -04:00
Douglas Christopher Wilson
f15bba7309 4.9.8 2014-10-17 22:01:51 -04:00
Alex Upadhyay
6f0302fb78 Fix res.redirect body when redirect status specified
fixes #2402
fixes #2404
2014-10-17 22:00:59 -04:00
Douglas Christopher Wilson
0e5613363f Use content-disposition module 2014-10-17 21:08:05 -04:00
Fishrock123
7a7f18c20b build: misc. updates to packaging
closes #2398
2014-10-17 20:49:56 -04:00
Douglas Christopher Wilson
b766aad112 deps: jade@~1.7.0 2014-10-17 20:45:57 -04:00
Douglas Christopher Wilson
7488e27609 deps: send@0.10.0 2014-10-17 20:45:09 -04:00
Douglas Christopher Wilson
bc9d854763 deps: depd@~1.0.0 2014-10-17 20:44:07 -04:00
Douglas Christopher Wilson
2e20a85810 deps: debug@~2.1.0 2014-10-17 20:43:23 -04:00
Douglas Christopher Wilson
a706408208 deps: connect@2.27.0 2014-10-17 20:42:12 -04:00
Douglas Christopher Wilson
6f91416020 deps: accepts@~1.1.2 2014-10-16 01:29:00 -04:00
Douglas Christopher Wilson
2c5ed88c90 Merge tag '3.17.8' 2014-10-16 01:27:44 -04:00
Douglas Christopher Wilson
6d39d0f8a8 3.17.8 2014-10-16 00:29:56 -04:00
Douglas Christopher Wilson
159ea67713 deps: connect@2.26.6 2014-10-16 00:24:28 -04:00
Douglas Christopher Wilson
33959ed350 deps: mocha@~1.21.5 2014-10-16 00:19:47 -04:00
Bessie Chan
be478d348c Fix typo in res.redirect deprecation
closes #2395
2014-10-11 18:11:22 -04:00
Douglas Christopher Wilson
b0e4e641f9 4.9.7 2014-10-10 16:40:46 -04:00
Douglas Christopher Wilson
94f10c26cb Fix using same param name in array of paths
fixes #2389
2014-10-10 16:31:09 -04:00
Douglas Christopher Wilson
efd2dfb8c8 4.9.6 2014-10-08 22:33:13 -04:00
Douglas Christopher Wilson
3f2454e3df deps: type-is@~1.5.2 2014-10-08 21:51:10 -04:00
Douglas Christopher Wilson
61da3c7d0e deps: serve-static@~1.6.4 2014-10-08 21:50:08 -04:00
Douglas Christopher Wilson
2c140961ab deps: accepts@~1.1.1 2014-10-08 21:48:27 -04:00
Douglas Christopher Wilson
6aa4a450ed Merge tag '3.17.7' 2014-10-08 21:45:42 -04:00
Douglas Christopher Wilson
9f292d873e 3.17.7 2014-10-08 17:00:45 -04:00
Douglas Christopher Wilson
ef3e95ca73 deps: supertest@~0.14.0 2014-10-08 16:44:29 -04:00
Douglas Christopher Wilson
f45bd632df deps: connect@2.26.5 2014-10-08 16:43:02 -04:00
Douglas Christopher Wilson
cc18da5cdf 3.17.6 2014-10-02 23:29:40 -04:00
Douglas Christopher Wilson
5603f86edd deps: connect@2.26.4 2014-10-02 23:27:41 -04:00
Douglas Christopher Wilson
daadf6033b 4.9.5 2014-09-24 20:18:59 -04:00
Douglas Christopher Wilson
590c919204 deps: serve-static@~1.6.3 2014-09-24 20:16:00 -04:00
Douglas Christopher Wilson
3bcba79e2d deps: etag@~1.4.0 2014-09-24 20:14:39 -04:00
Douglas Christopher Wilson
b8c8ecebb7 Merge tag '3.17.5' 2014-09-24 20:11:19 -04:00
Douglas Christopher Wilson
43e2cd79cb 3.17.5 2014-09-24 19:38:35 -04:00
Douglas Christopher Wilson
653270bb43 deps: send@0.9.3 2014-09-24 19:15:46 -04:00
Douglas Christopher Wilson
734bdf5ca1 deps: proxy-addr@~1.0.3 2014-09-24 19:14:33 -04:00
Douglas Christopher Wilson
341c1919d9 deps: connect@2.26.3 2014-09-24 19:12:43 -04:00
Douglas Christopher Wilson
8e46af1b1d 4.9.4 2014-09-19 23:07:58 -07:00
Douglas Christopher Wilson
e4fc09423e deps: qs@2.2.4 2014-09-19 23:06:31 -07:00
Douglas Christopher Wilson
0300b61fdd Merge tag '3.17.4' 2014-09-19 23:05:45 -07:00
Douglas Christopher Wilson
b09afad7b1 3.17.4 2014-09-19 22:57:07 -07:00
Douglas Christopher Wilson
0e0b259556 deps: connect@2.26.2 2014-09-19 22:54:39 -07:00
Douglas Christopher Wilson
bc38d896ea 4.9.3 2014-09-18 10:45:35 -07:00
Douglas Christopher Wilson
b2518fe135 Merge tag '3.17.3' 2014-09-18 10:43:35 -07:00
Douglas Christopher Wilson
63286e1192 3.17.3 2014-09-18 10:38:31 -07:00
Douglas Christopher Wilson
c00f2f8596 deps: proxy-addr@~1.0.2 2014-09-18 10:36:21 -07:00
Douglas Christopher Wilson
91891e3aee 4.9.2 2014-09-17 20:49:01 -07:00
Douglas Christopher Wilson
728917164c Fix router.use to accept array of middleware without path 2014-09-17 19:18:13 -07:00
Douglas Christopher Wilson
bf1980f1b4 Improve error message for bad app.use arguments 2014-09-17 19:18:10 -07:00
Douglas Christopher Wilson
3c1a964362 Fix regression for empty string path in app.use
fixes #2361
fixes #2362
2014-09-17 19:18:01 -07:00
Douglas Christopher Wilson
947fb8b274 4.9.1 2014-09-16 23:31:57 -07:00
Douglas Christopher Wilson
c5193536e5 deps: update example dependencies 2014-09-16 23:24:23 -07:00
Douglas Christopher Wilson
d08fd64190 deps: serve-static@~1.6.2 2014-09-16 23:23:14 -07:00
Douglas Christopher Wilson
2470ae6c72 deps: etag@~1.3.1 2014-09-16 23:21:45 -07:00
Douglas Christopher Wilson
916a75cf19 Merge tag '3.17.2' 2014-09-16 23:08:03 -07:00
Douglas Christopher Wilson
daacb749c1 deps: remove un-used buffer-crc32 dependency 2014-09-16 23:03:04 -07:00
Douglas Christopher Wilson
f29399c4e1 3.17.2 2014-09-16 00:14:41 -07:00
Douglas Christopher Wilson
f6ac068ab0 Use crc instead of buffer-crc32 for speed 2014-09-16 00:11:08 -07:00
Douglas Christopher Wilson
7eb65eeca2 deps: send@0.9.2 2014-09-15 23:59:02 -07:00
Douglas Christopher Wilson
178fe15091 deps: depd@0.4.5 2014-09-15 23:57:41 -07:00
Douglas Christopher Wilson
381f278d0a deps: connect@2.26.1 2014-09-15 23:56:36 -07:00
Douglas Christopher Wilson
534fa181c6 Add test-tap npm script for TAP output
closes #2359
2014-09-15 21:41:35 -07:00
Julien Gilli
80847d8c82 tests: fix broken tests with node v0.12 branch
Currently, test/req.ip.js assumes that the connection between the client
and the server is an IPv4 connection. However, depending on the
configuration of the host where this test runs, the connection can be an
IPv4 one or an IPv6 one using an IPv4 mapped address. In the future, it
could also be a "full" IPv6 connection.

This change makes this test handle any type of address.

fixes #2342
2014-09-15 21:41:34 -07:00
Fei Yao
bb8abf1f90 Remove unused require in router match
closes #2358
2014-09-14 09:14:24 -07:00
Douglas Christopher Wilson
cf41a8f254 Fix app.use to accept array of middleware without path
fixes #2356
2014-09-12 17:46:49 -04:00
Douglas Christopher Wilson
1716e3b067 4.9.0 2014-09-09 00:32:17 -04:00
Seth Samuel
12f92a50dc Add res.sendStatus
closes #2269
closes #2297
closes #2340
2014-09-09 00:24:11 -04:00
Douglas Christopher Wilson
51d33edb79 Use etag to generate ETag headers 2014-09-09 00:13:49 -04:00
Douglas Christopher Wilson
2a0c35a108 Invoke callback for sendfile when client aborts
fixes #2189
fixes #2300
closes #2303
closes #2305
2014-09-09 00:12:49 -04:00
Douglas Christopher Wilson
d4de82b853 deps: accepts@~1.1.0 2014-09-09 00:12:10 -04:00
Douglas Christopher Wilson
e2102263ce deps: serve-static@~1.6.1 2014-09-09 00:11:04 -04:00
Douglas Christopher Wilson
d2b1a89b4a deps: type-is@~1.5.1 2014-09-09 00:10:02 -04:00
Douglas Christopher Wilson
d9937c628a deps: finalhandler@0.2.0 2014-09-09 00:08:07 -04:00
Douglas Christopher Wilson
276db8c49a deps: update example dependencies 2014-09-09 00:06:27 -04:00
Douglas Christopher Wilson
1768d94a1a deps: qs@2.2.3 2014-09-09 00:04:08 -04:00
Douglas Christopher Wilson
6bc7574ab5 docs: typo fixes
closes #2316
2014-09-08 23:53:21 -04:00
Douglas Christopher Wilson
3dca534995 Merge tag '3.17.1' 2014-09-08 23:48:59 -04:00
Douglas Christopher Wilson
4b1b8e420f 3.17.1 2014-09-08 23:45:38 -04:00
Douglas Christopher Wilson
70767b19ac Fix error in req.subdomains on empty host 2014-09-08 23:45:34 -04:00
Douglas Christopher Wilson
7d277c1c15 docs: remove erroneous from history 2014-09-08 23:44:24 -04:00
Douglas Christopher Wilson
fa1fcd9fec 3.17.0 2014-09-08 23:07:02 -04:00
Douglas Christopher Wilson
2de6514b4b Support IP address host in req.subdomains
fixes #2308
2014-09-08 23:04:06 -04:00
Douglas Christopher Wilson
d07c06363f Support X-Forwarded-Host in req.subdomains 2014-09-08 23:02:42 -04:00
Douglas Christopher Wilson
4e97533fd2 deps: jade@~1.6.0 2014-09-08 22:48:47 -04:00
Douglas Christopher Wilson
d7d6219a1e deps: range-parser@~1.0.2 2014-09-08 22:47:54 -04:00
Douglas Christopher Wilson
9b18461bbc deps: vary@~1.0.0 2014-09-08 21:18:28 -04:00
Douglas Christopher Wilson
b77aa38c98 deps: cookie-signature@1.0.5 2014-09-08 21:17:03 -04:00
Douglas Christopher Wilson
cbb251377e deps: fresh@0.2.4 2014-09-08 21:14:27 -04:00
Douglas Christopher Wilson
d6ed469de3 deps: send@0.9.1 2014-09-08 21:13:20 -04:00
Douglas Christopher Wilson
49284c236b deps: debug@~2.0.0 2014-09-08 21:11:41 -04:00
Douglas Christopher Wilson
be18487f7d deps: media-typer@0.3.0 2014-09-08 21:10:57 -04:00
Douglas Christopher Wilson
094ff11949 deps: connect@2.26.0 2014-09-08 21:09:22 -04:00
lemmy
d2d0afff64 Remove unused variable
closes #2345
2014-09-08 20:59:03 -04:00
Douglas Christopher Wilson
33bb8fc4b6 examples: fix up route-separation code
closes #2341
2014-09-08 20:51:32 -04:00
Douglas Christopher Wilson
b97f6eb506 examples: fix github view example
closes #2344
2014-09-08 19:31:58 -04:00
Douglas Christopher Wilson
621d074bd8 4.8.8 2014-09-05 02:26:12 -04:00
Douglas Christopher Wilson
d7e7b2e7d7 deps: update example dependencies 2014-09-05 02:24:02 -04:00
Douglas Christopher Wilson
2d6b735b4f deps: serve-static@~1.5.4 2014-09-05 02:21:27 -04:00
Douglas Christopher Wilson
a3115882d4 Merge tag '3.16.10' 2014-09-05 02:20:02 -04:00
Douglas Christopher Wilson
3d188fe13e 3.16.10 2014-09-05 02:17:55 -04:00
Douglas Christopher Wilson
8327708ec2 deps: istanbul@0.3.2 2014-09-05 01:57:02 -04:00
Douglas Christopher Wilson
c8640b3465 deps: send@0.8.5 2014-09-05 01:56:27 -04:00
Douglas Christopher Wilson
3ce5f9b493 deps: connect@2.25.10 2014-09-05 01:55:24 -04:00
Douglas Christopher Wilson
46f0bfc65f 4.8.7 2014-08-30 01:37:52 -04:00
Douglas Christopher Wilson
0b49e7f1fd deps: update example dependencies 2014-08-30 01:33:05 -04:00
Douglas Christopher Wilson
f6f47f428c deps: qs@2.2.2 2014-08-30 01:30:56 -04:00
Douglas Christopher Wilson
20635d03fc Merge tag '3.16.9' 2014-08-30 01:28:38 -04:00
Douglas Christopher Wilson
4d032cda05 3.16.9 2014-08-30 01:22:06 -04:00
Douglas Christopher Wilson
4127ba10b0 deps: connect@2.25.9 2014-08-30 01:19:53 -04:00
Douglas Christopher Wilson
b6ae091bdf 4.8.6 2014-08-27 21:51:37 -04:00
Douglas Christopher Wilson
a206b4e273 deps: update example dependencies 2014-08-27 21:25:56 -04:00
Douglas Christopher Wilson
2b2733c235 deps: qs@2.2.0 2014-08-27 21:22:41 -04:00
Douglas Christopher Wilson
7fb7bcc0f7 Merge tag '3.16.8' 2014-08-27 21:20:53 -04:00
Douglas Christopher Wilson
0299bee8fa 3.16.8 2014-08-27 21:09:18 -04:00
Douglas Christopher Wilson
6a581c9961 deps: connect@2.25.8 2014-08-27 21:04:41 -04:00
Douglas Christopher Wilson
4986b1cb4c tests: add some res.sendfile directory tests 2014-08-24 13:28:39 -04:00
Douglas Christopher Wilson
3de4e4276d docs: fix logo link 2014-08-24 10:05:24 -04:00
Douglas Christopher Wilson
27f195374d 4.8.5 2014-08-18 23:05:16 -04:00
Douglas Christopher Wilson
ff0de5eb27 deps: update example dependencies 2014-08-18 23:00:01 -04:00
Douglas Christopher Wilson
f4ddef1570 deps: serve-static@~1.5.3 2014-08-18 22:58:47 -04:00
Douglas Christopher Wilson
9eafaa23d8 Merge tag '3.16.7' 2014-08-18 22:54:25 -04:00
Douglas Christopher Wilson
0b12cc0cac 3.16.7 2014-08-18 22:45:17 -04:00
Douglas Christopher Wilson
fdd0ccabe8 docs: flatten badges for github look 2014-08-18 22:45:13 -04:00
Douglas Christopher Wilson
8c36eab679 docs: use shields.io badges 2014-08-18 22:19:21 -04:00
Douglas Christopher Wilson
5c145b5490 build: add link to homepage 2014-08-18 22:17:25 -04:00
Raymond Feng
d7bef52591 build: move repository
closes #2268
closes #2270
2014-08-18 22:07:35 -04:00
Douglas Christopher Wilson
1576a95e87 deps: send@0.8.3 2014-08-18 21:57:29 -04:00
Douglas Christopher Wilson
7f92fe66e0 deps: connect@2.25.7 2014-08-18 21:41:14 -04:00
Douglas Christopher Wilson
0cf02d4667 4.8.4 2014-08-15 00:26:39 -04:00
Douglas Christopher Wilson
ef52b80d75 deps: update example dependencies 2014-08-15 00:24:28 -04:00
Douglas Christopher Wilson
1ca01c0c47 tests: add router.use validation tests
closes #2299
2014-08-15 00:22:54 -04:00
Douglas Christopher Wilson
fbceae2716 tests: add additional res.sendFile test
closes #2298
2014-08-15 00:18:54 -04:00
Douglas Christopher Wilson
ad3ca25c58 deps: qs@1.2.2 2014-08-15 00:16:20 -04:00
Douglas Christopher Wilson
666ffc62d8 deps: serve-static@~1.5.2 2014-08-15 00:15:28 -04:00
Douglas Christopher Wilson
6680132392 Merge tag '3.16.6' 2014-08-15 00:14:42 -04:00
Douglas Christopher Wilson
f13f4652da 3.16.6 2014-08-14 23:53:32 -04:00
Douglas Christopher Wilson
059c068c7b deps: send@0.8.2
fixes #2300
2014-08-14 23:52:07 -04:00
Douglas Christopher Wilson
49947f1476 deps: connect@2.25.6 2014-08-14 23:49:39 -04:00
Douglas Christopher Wilson
0dddd772c0 3.16.5 2014-08-11 22:30:09 -04:00
Douglas Christopher Wilson
0f87c6f392 deps: connect@2.25.5 2014-08-11 22:29:35 -04:00
Douglas Christopher Wilson
1643ae442c 4.8.3 2014-08-10 22:30:07 -04:00
Douglas Christopher Wilson
2594f3103b deps: serve-static@~1.5.1 2014-08-10 22:29:24 -04:00
Douglas Christopher Wilson
8473b3c338 deps: qs@1.2.1 2014-08-10 22:27:42 -04:00
Douglas Christopher Wilson
59cb99e9be Merge tag '3.16.4' 2014-08-10 22:26:49 -04:00
Douglas Christopher Wilson
7119f2b16d 3.16.4 2014-08-10 22:22:58 -04:00
Douglas Christopher Wilson
a57efea173 Fix original URL parsing in res.location 2014-08-10 22:20:54 -04:00
Douglas Christopher Wilson
4a4ca7347a deps: parseurl@~1.3.0 2014-08-10 22:19:10 -04:00
Douglas Christopher Wilson
570f60d36e deps: connect@2.25.4 2014-08-10 22:18:12 -04:00
Douglas Christopher Wilson
d13e613584 3.16.3 2014-08-07 22:32:16 -04:00
Douglas Christopher Wilson
9204e1f42a deps: connect@2.25.3 2014-08-07 22:31:53 -04:00
Douglas Christopher Wilson
22ca953e96 4.8.2 2014-08-07 12:05:02 -04:00
Douglas Christopher Wilson
7989c883fe deps: qs@1.2.0 2014-08-07 12:03:53 -04:00
Douglas Christopher Wilson
e05a52078a Merge tag '3.16.2' 2014-08-07 12:01:08 -04:00
Douglas Christopher Wilson
ddac571fdf 3.16.2 2014-08-07 11:59:54 -04:00
Douglas Christopher Wilson
982d24b475 deps: connect@2.25.2 2014-08-07 11:53:40 -04:00
Douglas Christopher Wilson
552b441f8a 4.8.1 2014-08-06 18:21:55 -04:00
Douglas Christopher Wilson
e8f8ea7e05 docs: update examples for deprecations 2014-08-06 18:13:54 -04:00
Douglas Christopher Wilson
4f5b27dd81 deps: update example dependencies 2014-08-06 18:10:32 -04:00
Douglas Christopher Wilson
cca88a7c47 Merge tag '3.16.1' 2014-08-06 18:09:15 -04:00
Douglas Christopher Wilson
ea427c1bb4 3.16.1 2014-08-06 18:07:31 -04:00
Douglas Christopher Wilson
0bd6c311cf deps: mocha@~1.21.4 2014-08-06 18:06:19 -04:00
Douglas Christopher Wilson
7f606ebf29 deps: connect@2.25.1 2014-08-06 18:05:50 -04:00
Douglas Christopher Wilson
a3b5adcf4a deps: qs@1.1.0 2014-08-06 17:50:08 -04:00
Douglas Christopher Wilson
1150ca7264 Fix incorrect deprecation warnings on res.download
fixes #2284
2014-08-06 17:48:36 -04:00
Douglas Christopher Wilson
4aea02310a 4.8.0 2014-08-06 02:50:59 -04:00
Fabien Franzen
17cea29013 Support mounted app as any argument to app.use()
fixes #2277
2014-08-06 02:49:06 -04:00
Douglas Christopher Wilson
8449f23f0d Deprecate res.sendfile 2014-08-06 02:27:16 -04:00
Douglas Christopher Wilson
2cb029f896 Add res.sendFile
fixes #1906
closes #2266
2014-08-06 02:26:51 -04:00
Douglas Christopher Wilson
7e32fa1be6 deps: update example dependencies 2014-08-06 01:59:09 -04:00
Douglas Christopher Wilson
1168d0bb8b deps: qs@1.0.2 2014-08-06 01:58:32 -04:00
Douglas Christopher Wilson
7d0f1c3db9 deps: serve-static@~1.5.0 2014-08-06 01:57:15 -04:00
Douglas Christopher Wilson
19abf7684b Merge tag '3.16.0' 2014-08-06 01:55:45 -04:00
Douglas Christopher Wilson
c652cf7eed 3.16.0 2014-08-06 01:40:46 -04:00
Douglas Christopher Wilson
19fd6f85b0 deps: connect-redis@~1.5.0 2014-08-06 01:39:12 -04:00
Douglas Christopher Wilson
b6c5b0511f deps: jade@~1.5.0 2014-08-06 01:37:58 -04:00
Douglas Christopher Wilson
0e42a37edd deps: send@0.8.1 2014-08-06 01:37:13 -04:00
Douglas Christopher Wilson
b24ed15878 deps: connect@2.25.0 2014-08-06 01:35:00 -04:00
Douglas Christopher Wilson
12e070e39a tests: add encoding tests for res.sendfile 2014-08-04 17:38:04 -04:00
Douglas Christopher Wilson
b886eb52cf 4.7.4 2014-08-04 17:36:37 -04:00
Douglas Christopher Wilson
d8237b976b Merge tag '3.15.3' into 4.7.x 2014-08-04 17:35:42 -04:00
Douglas Christopher Wilson
15590d75b2 3.15.3 2014-08-04 17:31:52 -04:00
Douglas Christopher Wilson
e8b471ff4f fix res.sendfile regression for serving directory index files 2014-08-04 17:30:25 -04:00
Douglas Christopher Wilson
767db01b79 deps: connect@2.24.3 2014-08-04 17:26:43 -04:00
Douglas Christopher Wilson
df413a41f3 deps: serve-static@~1.4.4 2014-08-04 17:14:32 -04:00
Douglas Christopher Wilson
52775a52ad 4.7.3 2014-08-04 16:14:29 -04:00
Douglas Christopher Wilson
112bc92d78 deps: serve-static@~1.4.3 2014-08-04 16:11:52 -04:00
Douglas Christopher Wilson
d8df26680f deps: send@0.7.3 2014-08-04 16:10:32 -04:00
Douglas Christopher Wilson
1854a5d35f 4.7.2 2014-07-27 16:00:54 -04:00
Douglas Christopher Wilson
54d3ffa9a0 deps: update example dependencies 2014-07-27 16:00:17 -04:00
Douglas Christopher Wilson
0ee4dd82b5 deps: serve-static@~1.4.2 2014-07-27 15:59:19 -04:00
Douglas Christopher Wilson
454c4b2350 Merge tag '3.15.2' 2014-07-27 15:58:45 -04:00
Douglas Christopher Wilson
696e150f0a 3.15.2 2014-07-27 15:53:45 -04:00
Douglas Christopher Wilson
819265c7ae deps: send@0.7.2 2014-07-27 15:41:54 -04:00
Douglas Christopher Wilson
baf8b14a71 deps: depd@0.4.4
fixes #2262
2014-07-27 15:41:19 -04:00
Douglas Christopher Wilson
06e7685d65 deps: connect@2.24.2 2014-07-27 15:40:19 -04:00
Douglas Christopher Wilson
8858f20d93 4.7.1 2014-07-26 18:53:26 -04:00
Douglas Christopher Wilson
65f67e2ec0 deps: serve-static@~1.4.1 2014-07-26 18:08:02 -04:00
Douglas Christopher Wilson
8e63521f68 Merge tag '3.15.1' 2014-07-26 18:06:11 -04:00
Douglas Christopher Wilson
9f4968aaa3 3.15.1 2014-07-26 17:42:18 -04:00
Douglas Christopher Wilson
afea3c0ae8 deps: mocha@~1.21.0 2014-07-26 17:36:42 -04:00
Douglas Christopher Wilson
edaabe66cf deps: send@0.7.1 2014-07-26 17:36:40 -04:00
Douglas Christopher Wilson
f724730e1a Adjust wording on deprecation messages 2014-07-26 17:36:39 -04:00
Douglas Christopher Wilson
e49d0dc9e3 deps: depd@0.4.3
fixes #2262
2014-07-26 17:36:24 -04:00
Douglas Christopher Wilson
e7a3fbaf48 deps: connect@2.24.1 2014-07-26 17:30:13 -04:00
Douglas Christopher Wilson
1a9a837c45 4.7.0 2014-07-25 20:26:11 -04:00
Douglas Christopher Wilson
ab8d116f42 tests: bail on failed test for developer 2014-07-23 18:17:31 -04:00
Douglas Christopher Wilson
d0b6b3dfcf tests: change Route tests to use callback 2014-07-23 17:28:14 -04:00
Douglas Christopher Wilson
f34944c539 Merge tag '3.15.0' 2014-07-23 16:15:00 -04:00
Ashley Streb
11c74d72eb Fix req.protocol for proxy-direct connections
fixes #2252
2014-07-23 16:08:20 -04:00
Douglas Christopher Wilson
035685918c deps: serve-static@~1.4.0 2014-07-23 14:56:27 -04:00
Douglas Christopher Wilson
88cffadcaa deps: send@0.7.0 2014-07-23 14:54:33 -04:00
Douglas Christopher Wilson
3b7ca43170 deps: jade@~1.5.0 2014-07-23 14:01:44 -04:00
Douglas Christopher Wilson
7cd86a01da deps: update example dependencies 2014-07-23 13:04:07 -04:00
Douglas Christopher Wilson
dc054d190a deps: parseurl@~1.2.0 2014-07-23 12:55:56 -04:00
Douglas Christopher Wilson
9019424725 deps: depd@0.4.2 2014-07-23 12:53:29 -04:00
Douglas Christopher Wilson
928952e7f0 3.15.0 2014-07-23 00:53:19 -04:00
Ashley Streb
a28b7a85cf Fix req.protocol for proxy-direct connections
fixes #2252
2014-07-23 00:19:10 -04:00
Douglas Christopher Wilson
3fc8dc54ee docs: replace Gittip badge 2014-07-23 00:13:21 -04:00
Douglas Christopher Wilson
0d77305a1a Pass options from res.sendfile to send
fixes #2017
2014-07-23 00:08:15 -04:00
Douglas Christopher Wilson
323c185079 deps: send@0.7.0 2014-07-23 00:05:45 -04:00
Douglas Christopher Wilson
1d0da9036b deps: parseurl@~1.2.0 2014-07-22 23:53:50 -04:00
Douglas Christopher Wilson
683ba1cd75 deps: depd@0.4.2 2014-07-22 23:52:44 -04:00
Douglas Christopher Wilson
e4ff5281c9 deps: connect@2.24.0 2014-07-22 23:50:36 -04:00
Douglas Christopher Wilson
7414a1f463 deps: debug@1.0.4 2014-07-18 14:18:35 -04:00
Douglas Christopher Wilson
fd3b40533b Deprecate combined status, response signatures
closes #2227
2014-07-17 22:49:41 -04:00
Douglas Christopher Wilson
21bb2ef30e deps: finalhandler@0.1.0 2014-07-16 20:47:24 -04:00
Douglas Christopher Wilson
da4c639954 deps: debug@1.0.4 2014-07-16 20:44:17 -04:00
Douglas Christopher Wilson
d046208ca2 build: add Young Jae Sim as contributor 2014-07-16 13:31:35 -04:00
Young Jae Sim
04f383087f docs: add expressjs.kr(expressjs.com in Korean)
closes #2242
closes #2244
2014-07-16 13:31:34 -04:00
Vasilyev Dmitry
fd86ab8da2 build: fix up jsdoc return values
closes #2243
2014-07-16 09:05:57 -04:00
Douglas Christopher Wilson
e29fa25bb4 Add configurable query parser
closes #2215
2014-07-13 23:15:00 -04:00
Douglas Christopher Wilson
b43205ca98 perf: prevent multiple Buffer creation in res.send 2014-07-13 21:14:30 -04:00
Douglas Christopher Wilson
112dbb2ab4 4.6.1 2014-07-12 22:11:48 -04:00
Douglas Christopher Wilson
3e32721e24 Fix subapp.mountpath regression for app.use(subapp)
fixes #2233
2014-07-12 22:07:43 -04:00
Douglas Christopher Wilson
8ba3f39b33 4.6.0 2014-07-11 23:31:30 -04:00
Douglas Christopher Wilson
82bdbad5e0 deps: finalhandler@0.0.3 2014-07-11 23:00:09 -04:00
Douglas Christopher Wilson
d29cf4d5e3 deps: serve-static@~1.3.2 2014-07-11 22:49:49 -04:00
Douglas Christopher Wilson
1623936a25 deps: send@0.6.0 2014-07-11 22:48:42 -04:00
Douglas Christopher Wilson
fa6a40526a deps: update example dependencies 2014-07-11 22:46:25 -04:00
Douglas Christopher Wilson
c6e6203020 perf: fix arguments reassign deopt in some res methods 2014-07-11 17:13:07 -04:00
Douglas Christopher Wilson
997a558a73 Accept multiple callbacks to app.use()
fixes #2224
2014-07-11 17:13:06 -04:00
Douglas Christopher Wilson
a01326adac Catch errors in multiple req.param(name, fn) handlers 2014-07-11 17:12:57 -04:00
Douglas Christopher Wilson
76e8bfa1dc router: refactor location of try blocks 2014-07-11 16:38:03 -04:00
Douglas Christopher Wilson
8dc67af606 router: speed up standard app.use(fn) 2014-07-11 16:37:10 -04:00
Douglas Christopher Wilson
996d319263 router: fix optimization on router exit 2014-07-11 16:36:20 -04:00
Douglas Christopher Wilson
1c3bd36be6 Support non-string path in app.use(path, fn)
fixes #2207
2014-07-11 16:35:37 -04:00
Douglas Christopher Wilson
4ea6f21b02 Merge tag '3.14.0' 2014-07-11 16:28:37 -04:00
Douglas Christopher Wilson
916c53737d 3.14.0 2014-07-11 13:11:31 -04:00
Douglas Christopher Wilson
ec5b9f5c61 tests: add test for error handler in route
closes #2228
2014-07-11 09:35:20 -04:00
Douglas Christopher Wilson
b2382a7336 Remove unnecessary escaping in res.jsonp 2014-07-11 00:20:11 -04:00
Douglas Christopher Wilson
f684a64df7 Add explicit "Rosetta Flash JSONP abuse" protection 2014-07-11 00:15:55 -04:00
Douglas Christopher Wilson
5d03d0eac8 Deprecate res.redirect(url, status) 2014-07-10 23:21:16 -04:00
Yad Smood
544c6665f5 Fix res.send(status, num) to send num as json
fixes #2226
2014-07-10 23:19:57 -04:00
Douglas Christopher Wilson
cf8005e63f deps: basic-auth@1.0.0 2014-07-10 23:07:45 -04:00
Douglas Christopher Wilson
25ef8425d2 deps: methods@1.1.0 2014-07-10 23:06:15 -04:00
Douglas Christopher Wilson
577cc1d1a0 deps: parseurl@~1.1.3 2014-07-10 23:03:26 -04:00
Douglas Christopher Wilson
3c87a6aede deps: debug@1.0.3 2014-07-10 23:02:24 -04:00
Douglas Christopher Wilson
7c1f90bf16 deps: istanbul@0.3.0 2014-07-10 22:57:08 -04:00
Douglas Christopher Wilson
7bcf5f5085 deps: connect@2.23.0 2014-07-10 22:56:31 -04:00
Ryan Seys
4fe1073f10 docs: fix nodejs.org link
closes #2222
2014-07-09 00:50:33 -04:00
Douglas Christopher Wilson
968b00c3d7 tests: add missing FQDN router URL tests 2014-07-08 19:40:22 -04:00
Douglas Christopher Wilson
ef497fdae4 tests: add mounting to strict routing test 2014-07-07 23:25:05 -04:00
Douglas Christopher Wilson
bcdeee2df5 4.5.1 2014-07-06 19:48:18 -04:00
Douglas Christopher Wilson
23a49ff61e Fix routing regression when altering req.method 2014-07-06 19:44:43 -04:00
Douglas Christopher Wilson
b4b2efee0f tests: add more app.use tests 2014-07-05 11:32:44 -04:00
Douglas Christopher Wilson
92c45199bd 4.5.0 2014-07-04 21:03:07 -04:00
Fishrock123
bd6908516d docs: cleanup readme, update package description
closes #2210
2014-07-04 17:05:48 -04:00
Douglas Christopher Wilson
e6eeec3f03 Add req.hostname
closes #2179
2014-07-04 14:00:37 -04:00
Douglas Christopher Wilson
269dc5323f Invoke router.param() only when route matches
fixes #2206
2014-07-04 13:46:23 -04:00
Douglas Christopher Wilson
efbc3f95ee deps: accepts@~1.0.7 2014-07-04 12:51:44 -04:00
Douglas Christopher Wilson
99e839a274 deps: update example dependencies 2014-07-04 01:24:42 -04:00
Douglas Christopher Wilson
32dbda1460 deps: istanbul@0.2.14 2014-07-04 01:23:14 -04:00
Douglas Christopher Wilson
bcee730354 Merge tag '3.13.0' 2014-07-04 01:14:40 -04:00
Douglas Christopher Wilson
abe0ffa311 3.13.0 2014-07-04 00:40:01 -04:00
Douglas Christopher Wilson
b601d64203 tests: fix inconsistent test 2014-07-04 00:38:59 -04:00
Douglas Christopher Wilson
f381f2d9b6 add deprecation message to req.auth 2014-07-04 00:24:01 -04:00
Douglas Christopher Wilson
12507cfcd0 deps: connect@2.22.0 2014-07-03 23:09:44 -04:00
Douglas Christopher Wilson
185e327e29 add deprecation message to app.configure 2014-07-03 14:13:39 -04:00
Douglas Christopher Wilson
c468f5ff20 deps: send@0.5.0 2014-07-03 13:10:33 -04:00
Douglas Christopher Wilson
ce3d1fe07e Add headers option to res.sendfile 2014-07-03 12:53:49 -04:00
Douglas Christopher Wilson
3136e98dce deps: send@0.5.0 2014-07-03 11:18:35 -04:00
Douglas Christopher Wilson
d1b1dfd472 deps: serve-static@~1.3.0 2014-07-03 11:11:18 -04:00
Douglas Christopher Wilson
ca306eace1 deps: update example dependencies 2014-07-03 10:49:53 -04:00
Douglas Christopher Wilson
fd35351594 Add mergeParams option to Router
fixes #2153
fixes #2203
2014-07-03 01:13:09 -04:00
Douglas Christopher Wilson
8a15f83d72 Merge tag '3.12.1' 2014-06-26 20:31:51 -04:00
Douglas Christopher Wilson
d91bf81c31 Merge tag '4.4.5' 2014-06-26 20:29:54 -04:00
Douglas Christopher Wilson
fd27f1f4e1 4.4.5 2014-06-26 20:26:43 -04:00
Douglas Christopher Wilson
f0ad557987 deps: cookie-signature@1.0.4 2014-06-26 20:25:20 -04:00
Douglas Christopher Wilson
9bb47fba30 3.12.1 2014-06-26 18:35:54 -04:00
Douglas Christopher Wilson
78d489d730 deps: cookie-signature@1.0.4 2014-06-26 18:26:34 -04:00
Douglas Christopher Wilson
8ffb9f9477 deps: connect@2.21.1 2014-06-26 18:25:48 -04:00
Douglas Christopher Wilson
9cb147370e deps: istanbul@0.2.12 2014-06-26 18:21:26 -04:00
Douglas Christopher Wilson
81036aa639 deps: finalhandler@0.0.2 2014-06-24 21:19:03 -04:00
Douglas Christopher Wilson
e7caaf6757 deps: type-is@~1.3.2 2014-06-24 21:18:12 -04:00
Douglas Christopher Wilson
a525252690 deps: istanbul@0.2.11 2014-06-24 21:15:43 -04:00
Douglas Christopher Wilson
0ebfc6b7bf tests: add test for OPTIONS in app.all 2014-06-23 20:35:44 -04:00
Douglas Christopher Wilson
381b3b0f77 add deprecation message to res.vary() 2014-06-23 16:26:28 -04:00
Douglas Christopher Wilson
ba8a4c5a8d add deprecation message to res.send(body, status) 2014-06-23 16:26:00 -04:00
Douglas Christopher Wilson
2cccbc186e add deprecation message to non-plural req.accepts* 2014-06-23 16:17:44 -04:00
Carlos Souza
83bbf0902d examples: tweak cors example
The PUT method needs clearance from the server, unlike GET, HEAD
and POST, so this demonstrates a case where the method in the
response is important.

closes #2195
2014-06-23 13:37:30 -04:00
Douglas Christopher Wilson
10618ced22 Reduce try-catch de-op area in param matching 2014-06-22 12:02:41 -04:00
Douglas Christopher Wilson
7f26cfca91 Fix handling when route.all is only route 2014-06-22 12:02:40 -04:00
Douglas Christopher Wilson
b89a597029 Restore req.params after invoking Router
fixes #2163
2014-06-22 12:02:36 -04:00
Guy Ellis Monster
746044b6c2 Replace __defineGetter__ with Object.defineProperty
closes #2162
2014-06-22 12:02:33 -04:00
Douglas Christopher Wilson
bdfd288eec fix behavior when handling request without routes
fixes #2159
2014-06-22 12:02:32 -04:00
Douglas Christopher Wilson
7e01531e50 use finalhandler for final response handling 2014-06-22 12:01:55 -04:00
Douglas Christopher Wilson
3ffceff3ed Merge tag '3.12.0' 2014-06-22 11:42:15 -04:00
Douglas Christopher Wilson
75422c16bf 3.12.0 2014-06-21 21:57:02 -04:00
Douglas Christopher Wilson
e66667e465 Use media-typer to alter content-type charset 2014-06-21 21:09:12 -04:00
Douglas Christopher Wilson
7d6208e0af deps: connect@2.21.0 2014-06-21 21:09:10 -04:00
Douglas Christopher Wilson
f498b660da 4.4.4 2014-06-20 16:56:51 -04:00
刘星
e606d99dc8 Fix res.attachment Unicode filenames in Safari
closes #2188
2014-06-20 16:55:05 -04:00
Douglas Christopher Wilson
6aba1b4c49 deps: accepts@~1.0.5 2014-06-20 16:44:50 -04:00
Douglas Christopher Wilson
6ee9433f29 deps: update example dependencies 2014-06-20 16:43:04 -04:00
Douglas Christopher Wilson
ffe663aedf deps: buffer-crc32@0.2.3 2014-06-20 00:35:38 -04:00
Douglas Christopher Wilson
2a105df9f2 3.11.0 2014-06-19 23:36:00 -04:00
Douglas Christopher Wilson
9c731f1883 deprecate things with depd module 2014-06-19 23:34:58 -04:00
Douglas Christopher Wilson
5a4e9125de deps: connect@2.20.2 2014-06-19 23:24:07 -04:00
Douglas Christopher Wilson
9db1367c2d deps: buffer-crc32@0.2.3 2014-06-19 22:55:21 -04:00
Douglas Christopher Wilson
8258ce14f4 fix "trim prefix" debug message in express:router
closes #2177
2014-06-14 12:57:32 -04:00
Douglas Christopher Wilson
ac573cf830 4.4.3 2014-06-12 00:41:24 -04:00
Douglas Christopher Wilson
e799c0fb7b Merge tag '3.10.5' 2014-06-12 00:38:29 -04:00
Douglas Christopher Wilson
73c5533e66 3.10.5 2014-06-12 00:28:08 -04:00
Douglas Christopher Wilson
3b1f747f96 deps: send@0.4.3 2014-06-12 00:24:21 -04:00
Douglas Christopher Wilson
9e9827d236 deps: debug@1.0.2 2014-06-12 00:23:15 -04:00
Douglas Christopher Wilson
a76d508424 deps: connect@2.19.6 2014-06-12 00:20:30 -04:00
Douglas Christopher Wilson
c361a06bd4 deps: serve-static@1.2.3 2014-06-12 00:17:28 -04:00
Douglas Christopher Wilson
3428543bb8 deps: accepts@1.0.3 2014-06-12 00:16:05 -04:00
Douglas Christopher Wilson
9cdbc80522 deps: send@0.4.3 2014-06-12 00:14:36 -04:00
Douglas Christopher Wilson
6775658ed5 Fix persistence of req.params from app.params
fixes #2170
2014-06-11 18:15:09 -04:00
Douglas Christopher Wilson
7df7f7a575 deps: debug@1.0.2 2014-06-11 17:53:56 -04:00
Douglas Christopher Wilson
7daae1912b 4.4.2 2014-06-09 20:40:39 -04:00
Douglas Christopher Wilson
3205f68510 deps: update example dependencies 2014-06-09 20:39:34 -04:00
Douglas Christopher Wilson
898dcfac8b Merge tag '3.10.4' 2014-06-09 20:39:22 -04:00
Douglas Christopher Wilson
b1efa19f97 deps: update testing dependencies 2014-06-09 20:24:36 -04:00
Douglas Christopher Wilson
b45fd70f99 deps: send@0.4.2 2014-06-09 20:22:42 -04:00
Douglas Christopher Wilson
7f6c7a19c6 deps: serve-static@1.2.2 2014-06-09 20:21:31 -04:00
Douglas Christopher Wilson
142462d539 deps: debug@1.0.1 2014-06-09 20:20:50 -04:00
Douglas Christopher Wilson
f881784e9b 3.10.4 2014-06-09 18:53:52 -04:00
Douglas Christopher Wilson
5af625903f deps: send@0.4.2 2014-06-09 18:51:55 -04:00
Douglas Christopher Wilson
dc94f305cc deps: debug@1.0.1 2014-06-09 18:50:36 -04:00
Douglas Christopher Wilson
8060a49c6c deps: connect@2.19.5 2014-06-09 18:50:00 -04:00
Douglas Christopher Wilson
4d3e0d88a2 Fix catching errors from top-level handlers 2014-06-09 09:44:37 -04:00
Nick Heiner
253ce4837a Use path.resolve for views dir instead of concat
closes #2165
2014-06-08 17:41:36 -04:00
Joshua Goldberg
ad05eb8222 Fix typo in console.log in multipart example
closes #2164
2014-06-07 20:14:33 -04:00
Douglas Christopher Wilson
21393c244c tests: add more route tests 2014-06-06 11:12:52 -04:00
Douglas Christopher Wilson
4279e6ef45 improve before hook in mvc example 2014-06-06 10:42:29 -04:00
Douglas Christopher Wilson
3db6dd752f change confusing 404 handling in download example 2014-06-06 10:23:47 -04:00
Douglas Christopher Wilson
fcbe68eeb5 docs: move badges 2014-06-06 00:41:08 -04:00
Douglas Christopher Wilson
5019f38e29 tests: add more tests 2014-06-06 00:38:14 -04:00
Douglas Christopher Wilson
9bf1247716 Merge tag '3.10.3' 2014-06-05 23:45:31 -04:00
Douglas Christopher Wilson
2fd31f6ea6 3.10.3 2014-06-05 23:38:58 -04:00
Douglas Christopher Wilson
9cf7bba8f0 deps: connect@2.19.4 2014-06-05 23:37:22 -04:00
Douglas Christopher Wilson
2e257d1cf7 build: use compressed formats in package 2014-06-05 19:45:00 -04:00
Douglas Christopher Wilson
980a15d847 deps: type-is@1.2.1 2014-06-05 19:40:27 -04:00
Douglas Christopher Wilson
56831d7799 deps: debug@1.0.0 2014-06-05 19:34:05 -04:00
Jonathan Ong
6d65ae5ba6 use vary@0.1.0
with backwards compatibility

closes #2161
2014-06-05 19:32:32 -04:00
Douglas Christopher Wilson
c919b4a573 3.10.2 2014-06-03 21:35:34 -04:00
Douglas Christopher Wilson
fe6f392c2d deps: connect@2.19.3 2014-06-03 21:33:55 -04:00
Douglas Christopher Wilson
bffb71d4c8 deps: proxy-addr@1.0.1 2014-06-03 17:25:20 -04:00
Douglas Christopher Wilson
3b34a537ee 3.10.1 2014-06-03 16:45:09 -04:00
Douglas Christopher Wilson
ad79ce9c4b deps: connect@2.19.2 2014-06-03 16:44:29 -04:00
Douglas Christopher Wilson
721f6388c3 deps: proxy-addr@1.0.1 2014-06-03 16:42:49 -04:00
Douglas Christopher Wilson
402ec83157 Merge tag '3.10.0' 2014-06-03 00:47:39 -04:00
Douglas Christopher Wilson
298ac11018 3.10.0 2014-06-03 00:40:27 -04:00
Douglas Christopher Wilson
bb6e207336 deps: connect@2.19.1 2014-06-03 00:37:57 -04:00
Douglas Christopher Wilson
f433b7c7cf replace utils.escape with html-escape 2014-06-03 00:37:32 -04:00
Douglas Christopher Wilson
a94278abd1 deps: send@0.4.1 2014-06-02 21:31:23 -04:00
Douglas Christopher Wilson
f9ec70edd0 4.4.1 2014-06-02 21:13:50 -04:00
Douglas Christopher Wilson
9e5a758e7c deps: update example dependencies 2014-06-02 20:59:45 -04:00
Douglas Christopher Wilson
492e933796 deps: serve-static@1.2.1 2014-06-02 20:50:54 -04:00
Douglas Christopher Wilson
8ccd9d0eb5 deps: send@0.4.1 2014-06-02 20:49:11 -04:00
Douglas Christopher Wilson
16fdc11ccb deps: methods@1.0.1 2014-06-02 20:48:18 -04:00
Douglas Christopher Wilson
a7cd5a2553 deps: methods@1.0.1 2014-06-02 19:19:56 -04:00
Douglas Christopher Wilson
9e6b881f85 remove jsdoc params for polymorphic functions
until jsdoc has a way to actually document them

closes #2156
2014-06-02 10:26:15 -04:00
Douglas Christopher Wilson
95fa49147b 4.4.0 2014-05-31 00:00:39 -04:00
Douglas Christopher Wilson
f665c57c5c update serve-static to 1.2.0 2014-05-30 22:53:02 -04:00
Douglas Christopher Wilson
9024d24e81 deps: supertest@~0.13.0 2014-05-30 22:50:22 -04:00
Douglas Christopher Wilson
f92a7ad0a3 update accepts to 1.0.2 2014-05-30 22:48:32 -04:00
Douglas Christopher Wilson
db4448dda8 Merge tag '3.9.0' 2014-05-30 22:17:51 -04:00
Douglas Christopher Wilson
0dc5836d5e 3.9.0 2014-05-30 21:35:12 -04:00
Douglas Christopher Wilson
8751d7ecf8 tests: add more tests 2014-05-30 21:28:48 -04:00
Douglas Christopher Wilson
c21226aa7c improve etag control for res.send
closes #1435
closes #2129
2014-05-30 21:02:21 -04:00
Douglas Christopher Wilson
3e358458f4 tests: add more etag tests 2014-05-30 19:51:32 -04:00
Douglas Christopher Wilson
766b3aecf7 deps: update example dependencies 2014-05-29 23:39:52 -04:00
Douglas Christopher Wilson
8ab96ab80d mark res.send ETag as weak and reduce collisions 2014-05-29 23:14:21 -04:00
Douglas Christopher Wilson
1f2e00ef8d deps: should@~4.0.0 2014-05-29 22:53:59 -04:00
Douglas Christopher Wilson
b49453cf0d update send to 0.4.0
closes #2150
2014-05-29 22:32:03 -04:00
Douglas Christopher Wilson
faffcb889c update connect to 2.18.0 2014-05-29 22:21:53 -04:00
Douglas Christopher Wilson
311e83e591 4.3.2 2014-05-29 00:17:21 -04:00
Tiago Relvao
3c0ec59432 Include ETag in HEAD requests
backport of commit 3c7310ebcb
2014-05-28 22:31:00 -04:00
Douglas Christopher Wilson
d4a2843500 tests: add param test with encoded value
closes #2143
2014-05-28 22:30:24 -04:00
Douglas Christopher Wilson
fb2d918056 fix handling of errors from param callbacks
fixes #2149
2014-05-28 22:26:05 -04:00
Douglas Christopher Wilson
e7ad49bbbe tests: add accepts test with params 2014-05-28 00:30:29 -04:00
Douglas Christopher Wilson
ad9a414fae tests: add more acceptance tests 2014-05-28 00:24:24 -04:00
Douglas Christopher Wilson
c18c2a8e68 tests: exclude untestable lines in examples from coverage 2014-05-28 00:07:27 -04:00
Douglas Christopher Wilson
1d54868c12 update supertest to 0.13.0 2014-05-27 23:54:34 -04:00
Douglas Christopher Wilson
dfefea5e9d update example dependencies 2014-05-27 23:51:47 -04:00
Douglas Christopher Wilson
3fbab91231 Merge tag '3.8.1' 2014-05-27 23:49:47 -04:00
Douglas Christopher Wilson
f7e73e2da0 3.8.1 2014-05-27 23:43:13 -04:00
Douglas Christopher Wilson
867728b5ab update connect to 2.17.3 2014-05-27 23:02:27 -04:00
Douglas Christopher Wilson
87e02c30e7 4.3.1 2014-05-23 19:11:28 -04:00
Douglas Christopher Wilson
c3470c9c96 tests: add route ordering test 2014-05-23 18:46:00 -04:00
Douglas Christopher Wilson
7f049164b7 Revert "fix behavior of multiple app.VERB for the same path"
This reverts commit 31b2e2d7b4.

fixes #2133
2014-05-23 18:35:20 -04:00
Douglas Christopher Wilson
4e12a72873 4.3.0 2014-05-21 02:13:03 -04:00
Douglas Christopher Wilson
91e0c27252 update example dependencies 2014-05-21 02:11:31 -04:00
Douglas Christopher Wilson
db4a061ed6 Merge tag '3.8.0' 2014-05-21 02:08:04 -04:00
Douglas Christopher Wilson
f6bbeafd26 3.8.0 2014-05-21 01:52:14 -04:00
Douglas Christopher Wilson
f14e39d451 set proper charset in content-type for res.send
This will write strings to sockets with an explicit "utf8" encoding
(which is the default) and will override the charset in the
Content-Type so it properly relfects the encoding of the response.

closes #1631
closes #2092
2014-05-21 01:31:08 -04:00
Alberto Leal
084f5d891b Keep previous Content-Type for res.jsonp
backport of commit be997fd654
2014-05-21 01:04:29 -04:00
Douglas Christopher Wilson
b0f72e13d9 update connect to 2.17.1 2014-05-21 00:55:10 -04:00
Douglas Christopher Wilson
8d7d80ef9d tests: add more tests of web-service example 2014-05-21 00:08:17 -04:00
Douglas Christopher Wilson
cf5de082b5 tests: add more tests of cookies example 2014-05-21 00:08:06 -04:00
Douglas Christopher Wilson
1944451082 tests: add more tests of negotiation example 2014-05-20 23:50:58 -04:00
Douglas Christopher Wilson
602e5a8200 tests: add more tests of mvc example 2014-05-20 23:41:09 -04:00
Douglas Christopher Wilson
83b8b7acb7 tests: add more various tests 2014-05-20 23:25:51 -04:00
Douglas Christopher Wilson
e660f19507 tests: add req.acceptsLanguage tests 2014-05-20 23:13:29 -04:00
Douglas Christopher Wilson
ff412b927d tests: add req.acceptsEncoding tests 2014-05-20 23:08:01 -04:00
Douglas Christopher Wilson
392ef1eb06 tests: add more app.render tests 2014-05-20 22:57:00 -04:00
Douglas Christopher Wilson
dcecdc9be6 update mocha to 1.19.0 2014-05-20 21:22:02 -04:00
Douglas Christopher Wilson
ed69b68892 update connect to 2.17.0 2014-05-20 21:20:56 -04:00
Douglas Christopher Wilson
42b982e13c build: remove coveralls from devDependencies 2014-05-20 20:22:55 -04:00
Douglas Christopher Wilson
e7e2592357 tests: add more app.param tests 2014-05-20 10:58:39 -04:00
Douglas Christopher Wilson
739586f96a add req.baseUrl to access stripped path in routes
fixes #2078
2014-05-19 00:39:26 -04:00
Douglas Christopher Wilson
4c0f1f53d3 update example dependencies 2014-05-18 23:07:59 -04:00
Douglas Christopher Wilson
359f12791a build: prevent failure from coveralls 2014-05-18 23:05:34 -04:00
Douglas Christopher Wilson
9354ab62dd build: prevent failure from coveralls 2014-05-18 23:02:25 -04:00
Douglas Christopher Wilson
23ff74bb3f tests: flow control with after 2014-05-18 16:33:11 -04:00
Douglas Christopher Wilson
98d17e2293 invoke router.param() only when necessary
fixes #2121
2014-05-18 16:21:01 -04:00
Douglas Christopher Wilson
ababa6ae5b fix issue routing requests among sub routers
fixes #2121
2014-05-18 15:27:28 -04:00
Douglas Christopher Wilson
097cd0c242 Merge tag '3.7.0' 2014-05-18 11:21:30 -04:00
Douglas Christopher Wilson
b91cd66fc5 3.7.0 2014-05-18 10:40:13 -04:00
Douglas Christopher Wilson
787d630157 update should to 3.3.1 2014-05-18 10:38:42 -04:00
Douglas Christopher Wilson
1f938c560a tests: improve examples/auth tests 2014-05-18 01:54:05 -04:00
Douglas Christopher Wilson
a96924a555 build: remove lib-cov fork 2014-05-18 01:35:12 -04:00
Douglas Christopher Wilson
33dc6629ff update connect to 2.16.2 2014-05-18 01:30:44 -04:00
Douglas Christopher Wilson
1b3fb0af8c build: add coverage reporting 2014-05-18 01:25:15 -04:00
Douglas Christopher Wilson
12da523ff7 build: test coverage with istanbul 2014-05-18 01:23:15 -04:00
Douglas Christopher Wilson
0f49d80623 build: clean up package file 2014-05-18 01:16:38 -04:00
Douglas Christopher Wilson
1717516a78 build: improve platform portability 2014-05-18 01:14:45 -04:00
Jonathan Ong
328c6d3060 remove unnecessary test/support/http
backport of 643397ed21
2014-05-18 00:57:54 -04:00
Douglas Christopher Wilson
566720be15 improve proxy trust with ip address list
closes #2099
2014-05-17 20:02:20 -04:00
Douglas Christopher Wilson
65f13c3cc6 update connect to 2.16.1 2014-05-17 14:30:52 -04:00
Douglas Christopher Wilson
31b2e2d7b4 fix behavior of multiple app.VERB for the same path
fixes #2116
2014-05-16 15:09:42 -04:00
Douglas Christopher Wilson
8fe8d74056 update type-is to 1.2.0 2014-05-14 00:25:39 -04:00
Douglas Christopher Wilson
fcc4742056 build: ignore Contributing 2014-05-14 00:22:47 -04:00
Douglas Christopher Wilson
d98e2e7498 deprecation messages are bright red on TTYs 2014-05-13 17:06:45 -04:00
Roman Shtylman
d37ffa1149 add Contributing.md
Hopefully this will guide some users when posting new issues. Feel free
to close any issues which don't follow the guidelines.
2014-05-12 15:45:54 -04:00
Douglas Christopher Wilson
cf709f3021 4.2.0 2014-05-11 22:00:30 -04:00
Douglas Christopher Wilson
7515ee6a78 deps: pin debug 2014-05-11 21:29:29 -04:00
Douglas Christopher Wilson
b8d6d258b0 update example dependencies 2014-05-11 21:25:42 -04:00
Douglas Christopher Wilson
35c50601bd Merge tag '3.6.0' 2014-05-09 17:33:26 -04:00
Douglas Christopher Wilson
f7be983a77 3.6.0 2014-05-09 17:03:23 -04:00
Douglas Christopher Wilson
bc9bcb0317 Fix req.next when inside router instance
fixes #2016
2014-05-09 16:53:15 -04:00
Douglas Christopher Wilson
a2553126dd support PURGE method 2014-05-09 10:19:20 -04:00
Douglas Christopher Wilson
0639c45acd build: add soft testing on node.js 0.11 2014-05-09 01:03:35 -04:00
Douglas Christopher Wilson
e4302b2120 tests: fixup new json tests 2014-05-08 23:22:18 -04:00
Douglas Christopher Wilson
3d6b4ba013 update example dependencies 2014-05-08 22:08:49 -04:00
Douglas Christopher Wilson
920f46ad65 tests: add more res.jsonp? tests 2014-05-08 21:27:01 -04:00
Douglas Christopher Wilson
35a66d8a14 tests: add test for res.format in route
closes #2016
2014-05-08 21:15:48 -04:00
Douglas Christopher Wilson
4e1e252e17 deprecate res.json(obj, status)
closes #2106
closes #2107
2014-05-08 21:11:05 -04:00
Douglas Christopher Wilson
0461e55380 deprecate app.del
closes #2095
2014-05-08 19:16:25 -04:00
Douglas Christopher Wilson
8dc4ff26f9 Add standard deprecation utility
* deprecations ignore when NODE_ENV=test
 * uses node.js util.deprecate
2014-05-08 19:01:16 -04:00
Roman Shtylman
6f9e927633 remove deprecation message about passing path as array
backport commit 6b19e3dc0a
2014-05-08 18:09:25 -04:00
Oliver Salzburg
40a43eb753 Value parameter of app.set() is now typed optional mixed 2014-05-08 17:04:14 -04:00
Douglas Christopher Wilson
a8bb4bab2b tests: add test for app.delete 2014-05-08 16:40:28 -04:00
Douglas Christopher Wilson
417999884b update supertest to 0.12.0 2014-05-08 16:29:41 -04:00
Douglas Christopher Wilson
17a739e35f update mkdirp to 0.5.0 2014-05-08 16:25:06 -04:00
Douglas Christopher Wilson
555ffe37b2 update history with dep history 2014-05-08 14:57:44 -04:00
Douglas Christopher Wilson
165578a1da update history 2014-05-08 14:48:24 -04:00
Douglas Christopher Wilson
0bbbc84959 Merge branch '4.1.x' 2014-05-08 14:45:47 -04:00
Douglas Christopher Wilson
92d37671c5 4.1.2 2014-05-08 14:42:44 -04:00
Douglas Christopher Wilson
2901bd6916 Merge branch '3.5.x' into 4.1.x 2014-05-08 14:01:02 -04:00
Douglas Christopher Wilson
66b38b58bc Merge branch '3.5.x' into 3.x 2014-05-08 13:55:00 -04:00
Douglas Christopher Wilson
4b646c2f8d docs: update core contributors 2014-05-07 23:08:55 -04:00
Douglas Christopher Wilson
35757ed1f5 docs: add NPM badge 2014-05-07 22:59:12 -04:00
Douglas Christopher Wilson
fed0d5df5c docs: use SVG badges 2014-05-07 22:57:05 -04:00
Douglas Christopher Wilson
0d468cbe6c update history 2014-05-05 00:42:50 -04:00
Douglas Christopher Wilson
f92ba6d0cf update connect to 2.15.0 2014-05-05 00:35:43 -04:00
Douglas Christopher Wilson
0408e3727e deps: debug@^0.8.0 2014-05-02 17:02:28 -04:00
Alberto Leal
be997fd654 Keep previous Content-Type for res.jsonp
closes #2094
2014-05-02 15:01:19 -04:00
Douglas Christopher Wilson
5c3852b91c tests: remove unused image fixture
closes #2091
2014-05-02 09:00:36 -04:00
Tiago Relvao
3c7310ebcb Include ETag in HEAD requests
fixes #2083
2014-04-30 09:34:10 -04:00
Douglas Christopher Wilson
61f2929a35 4.1.1 2014-04-27 19:49:05 -04:00
Douglas Christopher Wilson
c054581370 fix package.json to reflect supported node version
closes #2080
2014-04-27 19:46:53 -04:00
Douglas Christopher Wilson
dbea8312bb 4.1.0 2014-04-24 18:13:41 -04:00
Douglas Christopher Wilson
1536a2196e preserve casing of headers in res.header and res.set
fixes #2063
2014-04-24 18:00:43 -04:00
Douglas Christopher Wilson
374e6c3789 fix multipart example
closes #2061
2014-04-24 17:50:20 -04:00
Douglas Christopher Wilson
203fb05d3e update example dependencies 2014-04-24 17:05:20 -04:00
Douglas Christopher Wilson
ce8555c690 update should to 3.3.1 2014-04-24 16:51:49 -04:00
Douglas Christopher Wilson
9863fa0903 update serve-static to 1.1.0 2014-04-24 16:46:51 -04:00
Douglas Christopher Wilson
2fd3e72a19 Pass options from res.sendfile to send
fixes #2017
2014-04-24 16:44:06 -04:00
Douglas Christopher Wilson
8ccceacf91 Merge branch '3.x' 2014-04-24 16:43:51 -04:00
Douglas Christopher Wilson
6ac6305b53 Merge branch '3.x' into HEAD 2014-04-24 15:42:41 -04:00
Roman Shtylman
29e8ccef4e Merge pull request #2067 from swrh/mvc-example-ejs-to-jade
MVC example: EJS -> Jade.
2014-04-23 10:21:26 -04:00
Fernando Silveira
ce17efd95b MVC example: EJS -> Jade. 2014-04-23 00:13:26 -03:00
Roman Shtylman
5480cb9571 Merge pull request #2060 from swrh/master
examples: Fix bugs in MVC example
2014-04-22 23:09:49 -04:00
Fernando Silveira
b38ffd7376 Fixing bug in MVC example pet view. 2014-04-22 23:30:17 -03:00
Fernando Silveira
8d8f44f352 Fix "method-override" dependency.
Depend on method-override@1.0.0 strictly, following the pattern for (almost) all other devDependencies.
2014-04-22 22:46:52 -03:00
Roman Shtylman
af5f21b2e2 Merge pull request #2065 from WebReflection/patch-1
trim_prefix causing --use-strict flag to fail
2014-04-22 20:23:58 -04:00
Andrea Giammarchi
4ac7474e4e trim_prefix causing --use-strict flag to fail
as specified in bug #2064 the `trim_prefix` function declaration within the `try/catch` causes problems when starting express with `--use_strict` directive.
2014-04-22 17:02:54 -07:00
Roman Shtylman
bdb3bb98f6 Merge pull request #2058 from thetalecrafter/content-disposition
support non-ascii filenames in content-disposition headers
2014-04-21 22:12:38 -04:00
Fernando Silveira
896609c859 Fixing bug when updating pet name in MVC example. 2014-04-21 12:10:21 -03:00
Fernando Silveira
50158b851c Express 4 now uses "method-override" external library. 2014-04-21 12:08:34 -03:00
Andy VanWagoner
56b672e657 support non-ascii filenames in content-disposition headers 2014-04-19 21:16:11 -06:00
Jonathan Ong
b9e9576083 Readme: add Roman as lead maintainer
so people start emailing him instead of TJ :D
2014-04-18 00:28:43 -07:00
Chris Andrejewski
79cc5a4d27 make old middleware properties configurable
closes #2054
2014-04-16 08:49:08 -04:00
Roman Shtylman
5f1d57704e Merge pull request #2053 from shawnzhu/fix-xhr-test
improve req.xhr test by verifying status code
2014-04-15 09:34:16 -04:00
Ke Zhu
19983272f3 improve req.xhr test by verifying status code 2014-04-15 00:11:20 -04:00
Roman Shtylman
e1ab302234 Merge pull request #2047 from Pana/patch-1
remove one feature description
2014-04-14 10:51:35 -04:00
Wang
6b1c443212 remove one feature description 2014-04-13 22:05:49 +08:00
Jonathan Ong
b79a271553 update type-is@1.1.0 2014-04-12 17:25:33 -07:00
Douglas Christopher Wilson
260141ee08 add soft testing on node.js 0.11 2014-04-10 17:04:19 -04:00
Douglas Christopher Wilson
fb1232043d update cookie to 0.1.1 2014-04-10 16:59:41 -04:00
Douglas Christopher Wilson
2377fc8bcf update serve-static to 1.0.4 2014-04-10 16:59:40 -04:00
Douglas Christopher Wilson
c610902b67 update accepts to 1.0.1 2014-04-10 16:59:38 -04:00
Douglas Christopher Wilson
a802405e19 update type-is to 1.0.1 2014-04-10 16:59:36 -04:00
Douglas Christopher Wilson
0dbaacfe12 update history 2014-04-10 16:57:00 -04:00
Roman Shtylman
b8dd60dec7 update readme to v4 release
- remove 3.0.0 from logo
- remove RC status for v4

close #2036
2014-04-10 09:57:30 -04:00
Roman Shtylman
147c2507c3 4.0.0 2014-04-09 16:38:40 -04:00
Roman Shtylman
d72f27909f handle thrown errors inside Route
close #2029
2014-04-08 14:50:26 -04:00
Roman Shtylman
1ee5329b1c Merge pull request #2025 from seanlinsley/patch-1
Use SVG badges in Readme
2014-04-05 17:08:09 -04:00
Sean Linsley
ba0b046a95 Use SVG badges in Readme 2014-04-05 15:35:46 -05:00
Jonathan Ong
412eb2a9ce Merge pull request #2018 from Devrama/patch-1
This example does not work with express 4.x.
2014-03-31 17:09:15 -07:00
WON JONG YOO
dd8e279cac Not work..
This example does not work with express 4.x.
bodyParser() does not have multipart() anymore.
Multiparty module and middleware are added.
2014-03-31 16:52:22 -04:00
Jonathan Ong
642432cb5e Merge pull request #2013 from kentcdodds/patch-1
Tell me what I'm using that isn't allowed
2014-03-28 22:57:03 -07:00
Kent C. Dodds
001c9380be Tell me what I'm using that isn't allowed
I'm migrating and it would be useful in a large application to know what I'm using that's not allowed. I think lots of people would feel this way. Let me know if you would prefer a different implementation.
2014-03-28 06:19:29 -06:00
Jonathan Ong
2e830fff99 Merge pull request #2008 from agchou/clean-up-code
some code clean up
2014-03-27 15:22:49 -07:00
agchou
06dcb22ae2 clean up code consistency 2014-03-27 09:15:27 -07:00
Jonathan Ong
0120874b8e Merge pull request #2004 from agchou/clean-up-code
some code clean up
2014-03-25 15:30:34 -07:00
agchou
13475977af some code cleanup 2014-03-25 15:23:04 -07:00
Roman Shtylman
e36746363a 4.0.0-rc4 2014-03-24 22:53:35 -04:00
Roman Shtylman
1eba854f23 support arrays as middleware arguments to .VERB and .all
Express 3.x supported passing in arrays for sets of common middleware.
While there are better ways to do this, removing this feature causes
headache in upgrading for no real gain. We can support it without much
more code.
2014-03-23 21:29:59 -04:00
Roman Shtylman
6b19e3dc0a remove deprecation message about passing path as array 2014-03-23 21:07:37 -04:00
Roman Shtylman
cb1fbce46b don't call done twice for thrown errors inside parameterized routes
fixes #1995
2014-03-23 14:42:46 -04:00
Roman Shtylman
cc38cccae1 Merge pull request #1984 from blakeembrey/params-update
Override params each layer
2014-03-18 20:45:27 -04:00
Blake Embrey
efbe1779e3 Override params every layer. 2014-03-17 15:16:26 -03:00
Roman Shtylman
8e3d0a6569 remove license text from readme 2014-03-13 20:20:04 -04:00
Roman Shtylman
8bd5d54b0e update license year, tired of all the fluff issues about this 2014-03-13 16:27:34 -04:00
Roman Shtylman
4867cf1e7b Merge pull request #1964 from blakeembrey/modular-routing
keep route params from previous middleware matches
2014-03-13 12:29:48 -04:00
Roman Shtylman
3ea3250dbe examples: remove reference to app.router in static-files
closes #1974
2014-03-12 10:27:10 -04:00
Roman Shtylman
3bbcbfdcf9 4.0.0-rc3 2014-03-11 21:39:01 -04:00
Blake Embrey
c7e84d8044 Clean up code and syntax issues. 2014-03-10 13:19:03 -04:00
Blake Embrey
9ae1d0d22d Remove redundant .all function. 2014-03-10 13:18:23 -04:00
Blake Embrey
51e80ffd48 Add tests for dynamic mounting. 2014-03-10 13:16:39 -04:00
Blake Embrey
be52dbbaa1 Allow dynamic mounting with .use.
Retains params from the parent application.
2014-03-10 13:13:39 -04:00
Roman Shtylman
76147c78a1 change my contributor email to tag with expressjs 2014-03-09 22:49:33 -04:00
Jonathan Ong
59da745d6c add @jonathanong and @defunctzombie as contributors 2014-03-09 19:46:52 -07:00
Jonathan Ong
68996d7561 remove req.auth 2014-03-09 19:45:43 -07:00
Roman Shtylman
5e12bab5cc add better error messages for non-functions as middleware
Only functions are supported for [VERB](path, fn), use(path, fn) and
all(fn) calls in Router and Routes. This catches those errors earlier to
avoid checks during actual request processing.
2014-03-09 22:30:47 -04:00
Jonathan Ong
7693aa5464 use parseurl 2014-03-07 18:27:26 -08:00
Jonathan Ong
110f471efa lint 2014-03-07 18:04:03 -08:00
Jonathan Ong
2064f412cb remove res.charset usage 2014-03-07 16:46:54 -08:00
Jonathan Ong
3228fd3cbc remove res.charset support 2014-03-07 16:33:17 -08:00
Jonathan Ong
bad55f7977 move setHeader charset patch to .set
note that application/json no longer adds charset=utf-8. could be a
regression.

closes #1952
See also: https://github.com/broofa/node-mime/issues/86
2014-03-07 16:32:41 -08:00
Jonathan Ong
3cf7b2e39e refactor to use basic-auth 2014-03-07 16:18:51 -08:00
Jonathan Ong
b443da410a update History.md with 3.x branch 2014-03-06 14:59:36 -08:00
Jonathan Ong
b0351a08de Update History.md 2014-03-05 22:45:36 -08:00
Jonathan Ong
3321055025 use path-to-regexp 2014-03-05 22:35:55 -08:00
Jonathan Ong
5572897998 some jshint cleanup
some more errors but whatever
2014-03-05 22:24:35 -08:00
Jonathan Ong
3112f92d08 move the patch to the response proto 2014-03-05 22:20:58 -08:00
Jonathan Ong
74f55a863a remove .writeHead patch
no middleware uses the “header” event anymore
2014-03-05 22:17:25 -08:00
Jonathan Ong
9ea18e10c9 throw errors when users try to access removed middleware 2014-03-05 22:13:54 -08:00
Jonathan Ong
d84457b9c2 remoive legacy docs bin 2014-03-05 22:07:56 -08:00
Jonathan Ong
643397ed21 remove unnecessary test/support/http 2014-03-05 22:06:14 -08:00
Jonathan Ong
85bf9ab76a uncomment a commented out test
lol @visionmedia
2014-03-05 22:01:36 -08:00
Jonathan Ong
6ec1904aac use serve-static for static middleware 2014-03-05 21:58:49 -08:00
Roman Shtylman
f1315b9efa fix examples for express 4 (separate middleware)
close #1947
2014-03-05 10:36:05 -05:00
Jonathan Ong
a0e6bb5cb2 npm start to start the server! 2014-03-05 03:36:36 -08:00
Roman Shtylman
eaf63d94f0 4.0.0-rc2 2014-03-05 01:32:48 -05:00
Jonathan Ong
45500fba74 Update Readme.md 2014-03-04 21:32:22 -08:00
Jonathan Ong
8472effab3 Update Readme.md 2014-03-04 21:31:50 -08:00
Roman Shtylman
d368aed150 fix Route#all before Route#verb
Properly handle calling a VERB after using .all()

close #1945
2014-03-03 17:50:13 -05:00
Jonathan Ong
e3b60e80c0 Update Readme.md for Express 4 2014-03-02 23:32:51 -08:00
Roman Shtylman
9df10674f0 4.0.0-rc1 2014-03-02 11:17:29 -05:00
Roman Shtylman
e3617fb8ab Merge pull request #1941 from deiga/patch-1
Fixed deprecated example doctype
2014-03-01 10:08:32 -05:00
Timo Sand
0fbfce58c6 Fixed deprecated example doctype 2014-03-01 12:32:42 +02:00
Roman Shtylman
f8b954bcd9 make express.Router() return a Router function instance
Similar to how express() returns an express `app` instance which is also
a function, express.Router() returns the Router instance which is also a
function and can be easily used via another router or the app.

app.use(express.Router());
2014-02-26 20:22:11 -05:00
Roman Shtylman
caa25b506d Merge pull request #1935 from visionmedia/router-params-middleware
Router: add parameter handling to middleware
2014-02-25 12:35:13 -05:00
Roman Shtylman
6911815171 Router: add parameter handling to middleware
Middleware (.use) can now specify parameter arguments to trigger
Router.param loading. This is handy if you want to `.use` additional
routers but need to load certain objects before the mounted middleware
runs.
2014-02-23 19:21:13 -05:00
Roman Shtylman
0719e5f402 implement app.route() 2014-02-23 11:31:43 -05:00
Roman Shtylman
07b731add0 bump cookie parser dependency to 1.0.1 2014-02-22 09:26:30 -05:00
Roman Shtylman
d42d8f5b07 move support for multiple res.cookie calls to lib/response
Patch.js is simpler and follows upstream node.js closer as a result.
2014-02-22 09:26:30 -05:00
Roman Shtylman
143e72dd85 remove support for node 0.8 2014-02-22 09:26:30 -05:00
Roman Shtylman
6835289564 remove ServerResonse.headerSent monkey patch
node.js ServerResponse contains a headersSent field. Use that instead of
our patched misnamed version.
2014-02-22 09:26:29 -05:00
Roman Shtylman
1396e0855d remove last pieces of connect dependency
- copy over patch.js to shim ServerResponse
- bundle `static` middleware
2014-02-22 09:26:29 -05:00
Roman Shtylman
6a7363e4ae use local copy of parseUrl 2014-02-22 09:26:29 -05:00
Roman Shtylman
9bc63d92a0 move connect.query() into our repo 2014-02-22 09:26:29 -05:00
TJ Holowaychuk
6b05f60bad update node-fresh 2014-02-19 15:29:39 -08:00
Jonathan Ong
25e6629bcc update history 2014-02-08 11:40:48 -08:00
Jonathan Ong
0796c1d2d2 test app.router: ignore connect method
so tests pass in 0.11. 0.11 client seems to throw errors more often, so
this is not an issue with express or node’s servers.
2014-02-08 11:39:26 -08:00
Jonathan Ong
aac1d52c4f res.location: remove resolving relative urls
closes #1804

this is an unnecessary maintenance burden (see the number of removed
tests), especially when supporting mounting. browsers handle relative
locations, and so should all clients.

a regression could be absolute locations on a mounted app, but 1. we
can fix that later when someone complains and 2) code-smell
2014-02-08 11:37:43 -08:00
Roman Shtylman
f41d09a3cf remove app.router and refactor middleware processing
This is an overhaul of middleware processing, Router and Route. Connect is no
longer used to process the middleware stack. This functionality has been
split into two parts: middleware stack and default error response.

The entry point for request processing is the `app.handle` method. It
sets up the default error response handle (to run in the event of no
other error handler) and then triggers the app router (instance of
Router) to handle the request.

The app router `handle` function contains the middleware dispatch layer
previously in the connect codebase. This layer handle the logic for
dispatching `.use` calls (stripping paths if needed). The app contains a
base router `app._router`. New routes can be created and `.use`d on this
router to organize routes into files.

Routers now have the following methods `.use`, `.all`, `.param` which
are all public.

Additionally, Routers have a `.route(path)` method which returns a new
instance of Route for the requested path. Route(s) are isolated
middleware stacks and contain methods for the HTTP verbs as well as an
`.all` method to act similar to middleware. These methods are chainable
to easily describe requirements for a route.

  var route = Router.route('/foo'); // or 'app.route('/foo')'

  route
  .all(auth)
  .get(function(...) {})
  .all(more_checks)
  .post(function(...) {})

Any Route and Router methods which accept handlers also accept error
(arity 4) handlers which will also behave as expected.

Finally, the `app.router` getter has been removed. Middleware and
handlers are run IN THE ORDER they are seen in the file. This means that
code which injected the `app.router` and then added error handlers (or
other middleware) will need to be updated to move those handlers after
any requests added on the app object. The examples have been updated
accordingly. This is the largest breaking change to codebases in this
commit.
2014-02-03 15:59:52 -05:00
Roman Shtylman
4bf9cfd477 update merge-descriptors 2014-01-29 20:01:10 -05:00
Roman Shtylman
08cbc442f5 update cookie-signature to 1.0.3
Fix for timing attack
2014-01-29 20:00:23 -05:00
Roman Shtylman
a02dd201e6 update send to 0.2.0 2014-01-29 19:58:53 -05:00
TJ Holowaychuk
a5f7dcee04 update node-fresh 2014-01-29 12:17:16 -08:00
Roman Shtylman
0ddd761904 update range parser to 1.0.0
- License

see #1912
2014-01-29 10:00:28 -05:00
Roman Shtylman
991c2a9d05 Merge pull request #1908 from visionmedia/locals-object
change res.locals to a plain js object.
2014-01-28 14:23:52 -08:00
Roman Shtylman
4983c38298 change res.locals to a plain js object.
Anyone who wants something fancier should use modules.

- fixes annoyance with not being able to set 'name' property on locals
2014-01-27 19:17:29 -05:00
Roman Shtylman
337ab24899 remove unused require 2014-01-24 19:31:32 -05:00
Roman Shtylman
63c6a9c5ad use escape-html module to escape html
Another util bites the dust.
2014-01-24 19:21:21 -05:00
Roman Shtylman
718e68ffae use utils-merge module to mixin object properties 2014-01-24 19:16:37 -05:00
Roman Shtylman
f56a5f01c4 remove deprecated express.createServer() method
This has been warning about deprecation for a long time. Use `express()`
to instantiate an express app.
2014-01-19 14:05:12 -05:00
Roman Shtylman
b77ffe0228 Merge pull request #1904 from popomore/master
delete semicolon
2014-01-19 09:18:29 -08:00
Haoliang Gao
fd6439bb36 delete semicolon 2014-01-19 23:53:48 +08:00
Jonathan Ong
121f8d02f3 Merge pull request #1889 from vesln/send-null-undefined
update the tests to show a difference between `send(null)` and `send(und...
2014-01-14 09:17:04 -08:00
Roman Shtylman
5ddbb6965f Merge pull request #1868 from dpatti/smarter-router-auto-options
Automatic OPTIONS response breaks with multiple routers
2014-01-13 14:45:06 -08:00
Doug Patti
a3b5f6d07f prevent incorrect automatic OPTIONS responses
The router has automatic handling of OPTIONS based on the registered
routes, but if you make an OPTIONS request for an endpoint that does
not exist, then it will still return a 200 with nothing allowed.
Instead, we can let the request move on down the middleware chain. This
has two benefits: first, if the route was not defined and no other
middleware handles it, it will return with a 404. Secondly, if multiple
routers are used and a later one has the route or a custom OPTIONS
defined, the first router will not respond incorrectly.
2014-01-13 17:40:42 -05:00
Roman Shtylman
ac2cbef8be Merge pull request #1899 from visionmedia/remove-configure
Remove app.configure
2014-01-11 15:42:55 -08:00
Roman Shtylman
dff22e9d09 update history file with configure changes 2014-01-11 10:54:13 -05:00
Roman Shtylman
7282b50ad0 remove app.configure() 2014-01-11 10:53:54 -05:00
Roman Shtylman
8c059469fd No 'json spaces' by default
Json rendering can be handled by user tools or overridden in their own
app to behave as desired. Minimizes the use of magic env settings.
2014-01-11 10:53:36 -05:00
Roman Shtylman
8c3f153dd4 remove use of app.configure for view cache setting 2014-01-11 10:52:38 -05:00
Jonathan Ong
185b526e60 Merge pull request #1892 from matheusazzi/patch-1
Update to valid Jade Doctype
2014-01-04 19:23:44 -08:00
Matheus Azzi
38996b30b1 Update layout.jade 2014-01-05 01:14:38 -02:00
TJ Holowaychuk
827dfed7c2 Merge pull request #1890 from oliversalzburg/patch-1
Value parameter of app.set() should be typed optional Object
2014-01-04 18:12:52 -08:00
Oliver Salzburg
28af21baeb Value parameter of app.set() is now typed optional mixed 2014-01-04 22:05:19 +01:00
Oliver Salzburg
951c70496b Value parameter of app.set() should be typed optional Object 2014-01-04 17:50:27 +01:00
Veselin Todorov
a36eeb96f3 update the tests to show a difference between send(null) and send(undefiend) 2014-01-03 19:47:57 +02:00
Jonathan Ong
7018d3d0e6 history: req.params 2014-01-03 03:00:48 -08:00
Jonathan Ong
3f14b4de1f Merge pull request #1835 from visionmedia/change-req-params-to-object
change req.params to an object instead of an array
2014-01-03 03:00:13 -08:00
Jonathan Ong
26c0be4c4e improve history.md 2014-01-03 02:57:24 -08:00
Jonathan Ong
cec0c06a70 refactor req.is and req.accepts* 2014-01-03 02:50:09 -08:00
Jonathan Ong
476f8deb07 remove binary 2014-01-03 02:33:00 -08:00
TJ Holowaychuk
c6c71abf4d change req.params to an object instead of an array 2013-11-27 19:46:39 -08:00
209 changed files with 9032 additions and 4287 deletions

41
.gitignore vendored
View File

@@ -1,19 +1,26 @@
coverage.html
.DS_Store
lib-cov
*.seed
# OS X
.DS_Store*
Icon?
._*
# Windows
Thumbs.db
ehthumbs.db
Desktop.ini
# Linux
.directory
*~
# npm
node_modules
*.log
*.csv
*.dat
*.out
*.pid
*.swp
*.swo
*.gz
# Coveralls
coverage
# Benchmarking
benchmarks/graphs
testing
node_modules/
testing
.coverage_data
cover_html
test.js
.idea

View File

@@ -1,10 +0,0 @@
.git*
benchmarks/
docs/
examples/
support/
test/
testing.js
.DS_Store
coverage.html
lib-cov

View File

@@ -1,4 +1,10 @@
language: node_js
node_js:
- "0.8"
- "0.10"
- "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"

25
Contributing.md Normal file
View File

@@ -0,0 +1,25 @@
## Website Issues
Issues for the expressjs.com website go here https://github.com/strongloop/expressjs.com
## PRs and Code contributions
* Tests must pass.
* Follow existing coding style.
* If you fix a bug, add a test.
## Issues which are questions
We will typically close any vague issues or questions that are specific to some app you are writing. Please double check the docs and other references before being trigger happy with posting a question issue.
Things that will help get your question issue looked at:
* Full and runnable JS code.
* Clear description of the problem or unexpected behavior.
* Clear description of the expected result.
* Steps you have taken to debug it yourself.
If you post a question and do not outline the above items or make it easy for us to understand and reproduce your issue, it will be closed.

1247
History.md

File diff suppressed because it is too large Load Diff

View File

@@ -1,6 +1,6 @@
(The MIT License)
Copyright (c) 2009-2013 TJ Holowaychuk <tj@vision-media.ca>
Copyright (c) 2009-2014 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
@@ -19,4 +19,4 @@ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

View File

@@ -1,34 +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) \
--globals setImmediate,clearImmediate \
$(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
bench:
@$(MAKE) -C benchmarks
clean:
rm -f coverage.html
rm -fr lib-cov
.PHONY: test test-unit test-acceptance bench clean

179
Readme.md
View File

@@ -1,52 +1,78 @@
[![express logo](http://f.cl.ly/items/0V2S1n0K1i3y1c122g04/Screen%20Shot%202012-04-11%20at%209.59.42%20AM.png)](http://expressjs.com/)
[![Express Logo](https://i.cloudup.com/zfY6lL7eFa-3000x3000.png)](http://expressjs.com/)
Fast, unopinionated, minimalist web framework for [node](http://nodejs.org).
[![Build Status](https://secure.travis-ci.org/visionmedia/express.png)](http://travis-ci.org/visionmedia/express) [![Gittip](http://img.shields.io/gittip/visionmedia.png)](https://www.gittip.com/visionmedia/)
[![NPM Version][npm-image]][npm-url]
[![NPM Downloads][downloads-image]][downloads-url]
[![Build Status][travis-image]][travis-url]
[![Test Coverage][coveralls-image]][coveralls-url]
```js
var express = require('express');
var app = express();
var express = require('express')
var app = express()
app.get('/', function(req, res){
res.send('Hello World');
});
app.get('/', function (req, res) {
res.send('Hello World')
})
app.listen(3000);
app.listen(3000)
```
## Installation
### Installation
$ npm install -g express
## Quick Start
The quickest way to get started with express is to utilize the executable `express(1)` to generate an application as shown below:
Create the app:
$ npm install -g express
$ express /tmp/foo && cd /tmp/foo
Install dependencies:
$ npm install
Start the server:
$ node app
```bash
$ npm install express
```
## Features
* Built on [Connect](http://github.com/senchalabs/connect)
* Robust routing
* Focus on high performance
* Super-high test coverage
* HTTP helpers (redirection, caching, etc)
* View system supporting 14+ template engines
* Content negotiation
* Focus on high performance
* Environment based configuration
* Executable for generating applications quickly
* High test coverage
## Docs & Community
* [Website and Documentation](http://expressjs.com/) - [[website repo](https://github.com/strongloop/expressjs.com)]
* [#express](https://webchat.freenode.net/?channels=express) on freenode IRC
* [Github Organization](https://github.com/expressjs) for Official Middleware & Modules
* Visit the [Wiki](https://github.com/strongloop/express/wiki)
* [Google Group](https://groups.google.com/group/express-js) for discussion
* [Русскоязычная документация](http://jsman.ru/express/)
* [한국어 문서](http://expressjs.kr) - [[website repo](https://github.com/Hanul/expressjs.kr)]
**PROTIP** Be sure to read [Migrating from 3.x to 4.x](https://github.com/strongloop/express/wiki/Migrating-from-3.x-to-4.x) as well as [New features in 4.x](https://github.com/strongloop/express/wiki/New-features-in-4.x).
## Quick Start
The quickest way to get started with express is to utilize the executable [`express(1)`](https://github.com/expressjs/generator) to generate an application as shown below:
Install the executable. The executable's major version will match Express's:
```bash
$ npm install -g express-generator@4
```
Create the app:
```bash
$ express /tmp/foo && cd /tmp/foo
```
Install dependencies:
```bash
$ npm install
```
Start the server:
```bash
$ npm start
```
## Philosophy
@@ -54,73 +80,56 @@ app.listen(3000);
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
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),
Express does not force you to use any specific ORM or template engine. With support for over
14 template engines via [Consolidate.js](https://github.com/tj/consolidate.js),
you can quickly craft your perfect framework.
## More Information
## Examples
* [Website and Documentation](http://expressjs.com/) stored at [visionmedia/expressjs.com](https://github.com/visionmedia/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://jsman.ru/express/)
* Run express examples [online](https://runnable.com/express)
To view the examples, clone the Express repo & install the dependancies:
## Viewing Examples
```bash
$ git clone git://github.com/strongloop/express.git --depth 1
$ cd express
$ npm install
```
Clone the Express repo, then install the dev dependencies to install all the example / test suite dependencies:
Then run whichever example you want:
$ git clone git://github.com/visionmedia/express.git --depth 1
$ cd express
$ npm install
```bash
$ node examples/content-negotiation
```
Then run whichever tests you want:
## Tests
$ node examples/content-negotiation
To run the test suite, first install the dependancies, then run `npm test`:
You can also view live examples here:
```bash
$ npm install
$ npm test
```
<a href="https://runnable.com/express" target="_blank"><img src="https://runnable.com/external/styles/assets/runnablebtn.png" style="width:67px;height:25px;"></a>
### People
## Running Tests
The original author of Express is [TJ Holowaychuk](https://github.com/tj) [![TJ's Gratipay][gratipay-image-visionmedia]][gratipay-url-visionmedia]
To run the test suite, first invoke the following command within the repo, installing the development dependencies:
The current lead maintainer is [Douglas Christopher Wilson](https://github.com/dougwilson) [![Doug's Gratipay][gratipay-image-dougwilson]][gratipay-url-dougwilson]
$ npm install
[List of all contributors](https://github.com/strongloop/express/graphs/contributors)
Then run the tests:
### License
$ make test
[MIT](LICENSE)
## Contributors
https://github.com/visionmedia/express/graphs/contributors
## License
(The MIT License)
Copyright (c) 2009-2012 TJ Holowaychuk &lt;tj@vision-media.ca&gt;
Permission is hereby granted, free of charge, to any person obtaining
a copy of this software and associated documentation files (the
'Software'), to deal in the Software without restriction, including
without limitation the rights to use, copy, modify, merge, publish,
distribute, sublicense, and/or sell copies of the Software, and to
permit persons to whom the Software is furnished to do so, subject to
the following conditions:
The above copyright notice and this permission notice shall be
included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
[npm-image]: https://img.shields.io/npm/v/express.svg?style=flat
[npm-url]: https://npmjs.org/package/express
[downloads-image]: https://img.shields.io/npm/dm/express.svg?style=flat
[downloads-url]: https://npmjs.org/package/express
[travis-image]: https://img.shields.io/travis/strongloop/express.svg?style=flat
[travis-url]: https://travis-ci.org/strongloop/express
[coveralls-image]: https://img.shields.io/coveralls/strongloop/express.svg?style=flat
[coveralls-url]: https://coveralls.io/r/strongloop/express?branch=master
[gratipay-image-visionmedia]: https://img.shields.io/gratipay/visionmedia.svg?style=flat
[gratipay-url-visionmedia]: https://gratipay.com/visionmedia/
[gratipay-image-dougwilson]: https://img.shields.io/gratipay/dougwilson.svg?style=flat
[gratipay-url-dougwilson]: https://gratipay.com/dougwilson/

View File

@@ -1,423 +0,0 @@
#!/usr/bin/env node
/**
* Module dependencies.
*/
var program = require('commander')
, mkdirp = require('mkdirp')
, pkg = require('../package.json')
, version = pkg.version
, os = require('os')
, fs = require('fs');
// CLI
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)')
.option('-H, --hogan', 'add hogan.js engine support')
.option('-c, --css <engine>', 'add stylesheet <engine> support (less|stylus) (defaults to plain css)')
.option('-f, --force', 'force on non-empty directory')
.parse(process.argv);
// Path
var path = program.args.shift() || '.';
// end-of-line code
var eol = os.EOL
// Template engine
program.template = 'jade';
if (program.ejs) program.template = 'ejs';
if (program.jshtml) program.template = 'jshtml';
if (program.hogan) program.template = 'hjs';
/**
* Routes index template.
*/
var index = [
''
, '/*'
, ' * GET home page.'
, ' */'
, ''
, 'exports.index = function(req, res){'
, ' res.render(\'index\', { title: \'Express\' });'
, '};'
].join(eol);
/**
* Routes users template.
*/
var users = [
''
, '/*'
, ' * GET users listing.'
, ' */'
, ''
, 'exports.list = function(req, res){'
, ' res.send("respond with a resource");'
, '};'
].join(eol);
/**
* Jade layout template.
*/
var jadeLayout = [
'doctype html'
, 'html'
, ' head'
, ' title= title'
, ' link(rel=\'stylesheet\', href=\'/stylesheets/style.css\')'
, ' body'
, ' block content'
].join(eol);
/**
* Jade index template.
*/
var jadeIndex = [
'extends layout'
, ''
, 'block content'
, ' h1= title'
, ' p Welcome to #{title}'
].join(eol);
/**
* EJS index template.
*/
var ejsIndex = [
'<!DOCTYPE html>'
, '<html>'
, ' <head>'
, ' <title><%= title %></title>'
, ' <link rel=\'stylesheet\' href=\'/stylesheets/style.css\' />'
, ' </head>'
, ' <body>'
, ' <h1><%= title %></h1>'
, ' <p>Welcome to <%= title %></p>'
, ' </body>'
, '</html>'
].join(eol);
/**
* JSHTML layout template.
*/
var jshtmlLayout = [
'<!DOCTYPE html>'
, '<html>'
, ' <head>'
, ' <title> @write(title) </title>'
, ' <link rel=\'stylesheet\' href=\'/stylesheets/style.css\' />'
, ' </head>'
, ' <body>'
, ' @write(body)'
, ' </body>'
, '</html>'
].join(eol);
/**
* JSHTML index template.
*/
var jshtmlIndex = [
'<h1>@write(title)</h1>'
, '<p>Welcome to @write(title)</p>'
].join(eol);
/**
* Hogan.js index template.
*/
var hoganIndex = [
'<!DOCTYPE html>'
, '<html>'
, ' <head>'
, ' <title>{{ title }}</title>'
, ' <link rel=\'stylesheet\' href=\'/stylesheets/style.css\' />'
, ' </head>'
, ' <body>'
, ' <h1>{{ title }}</h1>'
, ' <p>Welcome to {{ title }}</p>'
, ' </body>'
, '</html>'
].join(eol);
/**
* Default css template.
*/
var css = [
'body {'
, ' padding: 50px;'
, ' font: 14px "Lucida Grande", Helvetica, Arial, sans-serif;'
, '}'
, ''
, 'a {'
, ' color: #00B7FF;'
, '}'
].join(eol);
/**
* Default less template.
*/
var less = [
'body {'
, ' padding: 50px;'
, ' font: 14px "Lucida Grande", Helvetica, Arial, sans-serif;'
, '}'
, ''
, 'a {'
, ' color: #00B7FF;'
, '}'
].join(eol);
/**
* Default stylus template.
*/
var stylus = [
'body'
, ' padding: 50px'
, ' font: 14px "Lucida Grande", Helvetica, Arial, sans-serif'
, 'a'
, ' color: #00B7FF'
].join(eol);
/**
* App template.
*/
var app = [
''
, '/**'
, ' * Module dependencies.'
, ' */'
, ''
, '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\', path.join(__dirname, \'views\'));'
, 'app.set(\'view engine\', \':TEMPLATE\');'
, 'app.use(express.favicon());'
, 'app.use(express.logger(\'dev\'));'
, '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\')));'
, ''
, '// development only'
, 'if (\'development\' == app.get(\'env\')) {'
, ' app.use(express.errorHandler());'
, '}'
, ''
, 'app.get(\'/\', routes.index);'
, 'app.get(\'/users\', user.list);'
, ''
, 'http.createServer(app).listen(app.get(\'port\'), function(){'
, ' console.log(\'Express server listening on port \' + app.get(\'port\'));'
, '});'
, ''
].join(eol);
// Generate application
(function createApplication(path) {
emptyDirectory(path, function(empty){
if (empty || program.force) {
createApplicationAt(path);
} else {
program.confirm('destination is not empty, continue? ', function(ok){
if (ok) {
process.stdin.destroy();
createApplicationAt(path);
} else {
abort('aborting');
}
});
}
});
})(path);
/**
* Create application at the given directory `path`.
*
* @param {String} path
*/
function createApplicationAt(path) {
console.log();
process.on('exit', function(){
console.log();
console.log(' install dependencies:');
console.log(' $ cd %s && npm install', path);
console.log();
console.log(' run the app:');
console.log(' $ node app');
console.log();
});
mkdir(path, function(){
mkdir(path + '/public');
mkdir(path + '/public/javascripts');
mkdir(path + '/public/images');
mkdir(path + '/public/stylesheets', function(){
switch (program.css) {
case 'less':
write(path + '/public/stylesheets/style.less', less);
break;
case 'stylus':
write(path + '/public/stylesheets/style.styl', stylus);
break;
default:
write(path + '/public/stylesheets/style.css', css);
}
});
mkdir(path + '/routes', function(){
write(path + '/routes/index.js', index);
write(path + '/routes/user.js', users);
});
mkdir(path + '/views', function(){
switch (program.template) {
case 'ejs':
write(path + '/views/index.ejs', ejsIndex);
break;
case 'jade':
write(path + '/views/layout.jade', jadeLayout);
write(path + '/views/index.jade', jadeIndex);
break;
case 'jshtml':
write(path + '/views/layout.jshtml', jshtmlLayout);
write(path + '/views/index.jshtml', jshtmlIndex);
break;
case 'hjs':
write(path + '/views/index.hjs', hoganIndex);
break;
}
});
// CSS Engine support
switch (program.css) {
case 'less':
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(path.join(__dirname, \'public\')));');
break;
default:
app = app.replace('{css}', '');
}
// Session support
app = app.replace('{sess}', program.sessions
? eol + 'app.use(express.cookieParser(\'your secret here\'));' + eol + 'app.use(express.session());'
: '');
// Template support
app = app.replace(':TEMPLATE', program.template);
// package.json
var pkg = {
name: 'application-name'
, version: '0.0.1'
, private: true
, scripts: { start: 'node app.js' }
, dependencies: {
express: version
}
}
if (program.template) pkg.dependencies[program.template] = '*';
// CSS Engine support
switch (program.css) {
case 'less':
pkg.dependencies['less-middleware'] = '~0.1.15';
break;
default:
if (program.css) {
pkg.dependencies[program.css] = '*';
}
}
write(path + '/package.json', JSON.stringify(pkg, null, 2));
write(path + '/app.js', app);
});
}
/**
* Check if the given directory `path` is empty.
*
* @param {String} path
* @param {Function} fn
*/
function emptyDirectory(path, fn) {
fs.readdir(path, function(err, files){
if (err && 'ENOENT' != err.code) throw err;
fn(!files || !files.length);
});
}
/**
* echo str > path.
*
* @param {String} path
* @param {String} str
*/
function write(path, str) {
fs.writeFile(path, str);
console.log(' \x1b[36mcreate\x1b[0m : ' + path);
}
/**
* Mkdir -p.
*
* @param {String} path
* @param {Function} fn
*/
function mkdir(path, fn) {
mkdirp(path, 0755, function(err){
if (err) throw err;
console.log(' \033[36mcreate\033[0m : ' + path);
fn && fn();
});
}
/**
* Exit with the given `str`.
*
* @param {String} str
*/
function abort(str) {
console.error(str);
process.exit(1);
}

View File

@@ -2,8 +2,10 @@
* Module dependencies.
*/
var express = require('../..')
, hash = require('./pass').hash;
var express = require('../..');
var hash = require('./pass').hash;
var bodyParser = require('body-parser');
var session = require('express-session');
var app = module.exports = express();
@@ -14,15 +16,18 @@ app.set('views', __dirname + '/views');
// middleware
app.use(express.bodyParser());
app.use(express.cookieParser('shhhh, very secret'));
app.use(express.session());
app.use(bodyParser.urlencoded({ extended: false }));
app.use(session({
resave: false, // don't save session if unmodified
saveUninitialized: false, // don't create session until something stored
secret: 'shhhh, very secret'
}));
// Session-persisted message middleware
app.use(function(req, res, next){
var err = req.session.error
, msg = req.session.success;
var err = req.session.error;
var msg = req.session.success;
delete req.session.error;
delete req.session.success;
res.locals.message = '';
@@ -62,7 +67,7 @@ function authenticate(name, pass, fn) {
if (err) return fn(err);
if (hash == user.hash) return fn(null, user);
fn(new Error('invalid password'));
})
});
}
function restrict(req, res, next) {
@@ -75,7 +80,7 @@ function restrict(req, res, next) {
}
app.get('/', function(req, res){
res.redirect('login');
res.redirect('/login');
});
app.get('/restricted', restrict, function(req, res){
@@ -98,9 +103,9 @@ app.post('/login', function(req, res){
authenticate(req.body.username, req.body.password, function(err, user){
if (user) {
// Regenerate session when signing in
// to prevent fixation
// to prevent fixation
req.session.regenerate(function(){
// Store the user's primary key
// Store the user's primary key
// in the session store to be retrieved,
// or in this case the entire user object
req.session.user = user;
@@ -113,11 +118,12 @@ app.post('/login', function(req, res){
req.session.error = 'Authentication failed, please check your '
+ ' username and password.'
+ ' (use "tj" and "foobar")';
res.redirect('login');
res.redirect('/login');
}
});
});
/* istanbul ignore next */
if (!module.parent) {
app.listen(3000);
console.log('Express started on port 3000');

View File

@@ -1,5 +1,5 @@
// check out https://github.com/visionmedia/node-pwd
// check out https://github.com/tj/node-pwd
/**
* Module dependencies.

View File

@@ -1,6 +1,10 @@
/**
* Module dependencies.
*/
var express = require('../..')
, app = express();
var express = require('../..');
var logger = require('morgan');
var app = express();
app.set('views', __dirname);
app.set('view engine', 'jade');
@@ -14,11 +18,14 @@ while (n--) {
pets.push({ name: 'Jane', age: 6, species: 'ferret' });
}
app.use(express.logger('dev'));
app.use(logger('dev'));
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');
}

View File

@@ -1,4 +1,3 @@
var users = [];
users.push({ name: 'Tobi' });

View File

@@ -1,8 +1,8 @@
var express = require('../../')
, app = module.exports = express()
, users = require('./db');
var express = require('../../');
var app = module.exports = express();
var users = require('./db');
// so either you can deal with different types of formatting
// so either you can deal with different types of formatting
// for expected response in index.js
app.get('/', function(req, res){
res.format({
@@ -21,7 +21,7 @@ app.get('/', function(req, res){
json: function(){
res.json(users);
}
})
});
});
// or you could write a tiny middleware like
@@ -32,12 +32,13 @@ function format(path) {
var obj = require(path);
return function(req, res){
res.format(obj);
}
};
}
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');
}

View File

@@ -1,4 +1,3 @@
/**
* Module dependencies.
*/
@@ -7,14 +6,8 @@ var express = require('../../');
var app = module.exports = express();
// ignore GET /favicon.ico
app.use(express.favicon());
// pass a secret to cookieParser() for signed cookies
app.use(express.cookieParser('manny is cool'));
// add req.session cookie support
app.use(express.cookieSession());
app.use(cookieSession({ secret: 'manny is cool' }));
// do something with the session
app.use(count);
@@ -26,7 +19,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');
}

View File

@@ -1,31 +1,24 @@
/**
* Module dependencies.
*/
var express = require('../../')
, app = module.exports = express();
// add favicon() before logger() so
// GET /favicon.ico requests are not
// logged, because this middleware
// reponds to /favicon.ico and does not
// call next()
app.use(express.favicon());
var express = require('../../');
var app = module.exports = express();
var logger = require('morgan');
var cookieParser = require('cookie-parser');
var bodyParser = require('body-parser');
// custom log format
if ('test' != process.env.NODE_ENV)
app.use(express.logger(':method :url'));
if ('test' != process.env.NODE_ENV) app.use(logger(':method :url'));
// parses request cookies, populating
// req.cookies and req.signedCookies
// when the secret is passed, used
// when the secret is passed, used
// for signing the cookies.
app.use(express.cookieParser('my secret here'));
app.use(cookieParser('my secret here'));
// parses json, x-www-form-urlencoded, and multipart/form-data
app.use(express.bodyParser());
// parses x-www-form-urlencoded
app.use(bodyParser.urlencoded({ extended: false }));
app.get('/', function(req, res){
if (req.cookies.remember) {
@@ -48,7 +41,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');
}
}

View File

@@ -1,46 +0,0 @@
/**
* Module dependencies.
*/
var express = require('../..')
, app = express()
, api = express();
// app middleware
app.use(express.static(__dirname + '/public'));
// api middleware
api.use(express.logger('dev'));
api.use(express.bodyParser());
/**
* CORS support.
*/
api.all('*', function(req, res, next){
if (!req.get('Origin')) return next();
// use "*" here to accept any origin
res.set('Access-Control-Allow-Origin', 'http://localhost:3000');
res.set('Access-Control-Allow-Methods', 'GET, POST');
res.set('Access-Control-Allow-Headers', 'X-Requested-With, Content-Type');
// res.set('Access-Control-Allow-Max-Age', 3600);
if ('OPTIONS' == req.method) return res.send(200);
next();
});
/**
* POST a user.
*/
api.post('/user', function(req, res){
console.log(req.body);
res.send(201);
});
app.listen(3000);
api.listen(3001);
console.log('app listening on 3000');
console.log('api listening on 3001');

View File

@@ -1,12 +0,0 @@
<!DOCTYPE html>
<html>
<body>
<script>
var req = new XMLHttpRequest;
req.open('POST', 'http://localhost:3001/user', false);
req.setRequestHeader('Content-Type', 'application/json');
req.send('{"name":"tobi","species":"ferret"}');
console.log(req.responseText);
</script>
</body>
</html>

View File

@@ -1,44 +0,0 @@
/**
* Module dependencies.
*/
var express = require('../../')
, app = module.exports = express();
app.get('/', function(req, res){
res.send('<ul>'
+ '<li>Download <a href="/files/amazing.txt">amazing.txt</a>.</li>'
+ '<li>Download <a href="/files/missing.txt">missing.txt</a>.</li>'
+ '</ul>');
});
// /files/* is accessed via req.params[0]
// but here we name it :file
app.get('/files/:file(*)', function(req, res, next){
var file = req.params.file
, path = __dirname + '/files/' + file;
res.download(path);
});
// error handling middleware. Because it's
// below our routes, you will be able to
// "intercept" errors, otherwise Connect
// will respond with 500 "Internal Server Error".
app.use(function(err, req, res, next){
// special-case 404s,
// remember you could
// render a 404 template here
if (404 == err.status) {
res.statusCode = 404;
res.send('Cant find that file, sorry!');
} else {
next(err);
}
});
if (!module.parent) {
app.listen(3000);
console.log('Express started on port 3000');
}

View File

@@ -0,0 +1,2 @@
Only for test.
The file name is faked.

View File

@@ -0,0 +1 @@
한中日

View File

@@ -0,0 +1,36 @@
/**
* Module dependencies.
*/
var express = require('../../');
var app = module.exports = express();
app.get('/', function(req, res){
res.send('<ul>'
+ '<li>Download <a href="/files/amazing.txt">amazing.txt</a>.</li>'
+ '<li>Download <a href="/files/utf-8 한中日.txt">utf-8 한中日.txt</a>.</li>'
+ '<li>Download <a href="/files/missing.txt">missing.txt</a>.</li>'
+ '<li>Download <a href="/files/CCTV大赛上海分赛区.txt">CCTV大赛上海分赛区.txt</a>.</li>'
+ '</ul>');
});
// /files/* is accessed via req.params[0]
// but here we name it :file
app.get('/files/:file(*)', function(req, res, next){
var file = req.params.file;
var path = __dirname + '/files/' + file;
res.download(path, function(err){
if (!err) return; // file sent
if (err && err.status !== 404) return next(err); // non-404 error
// file for download not found
res.statusCode = 404;
res.send('Cant find that file, sorry!');
});
});
/* istanbul ignore next */
if (!module.parent) {
app.listen(3000);
console.log('Express started on port 3000');
}

View File

@@ -1,4 +1,3 @@
/**
* Module dependencies.
*/
@@ -44,7 +43,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');
}

View File

@@ -2,13 +2,14 @@
* Module dependencies.
*/
var express = require('../../')
, app = module.exports = express()
, silent = 'test' == process.env.NODE_ENV;
var express = require('../../');
var app = module.exports = express();
var logger = require('morgan');
var silent = 'test' == process.env.NODE_ENV;
// general config
app.set('views', __dirname + '/views');
app.set('view engine', 'jade');
app.set('view engine', 'ejs');
// our custom "verbose errors" setting
// which we can use in the templates
@@ -17,22 +18,36 @@ 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());
silent || app.use(logger('dev'));
silent || app.use(express.logger('dev'));
// Routes
// "app.router" positions our routes
// above the middleware defined below,
// this means that Express will attempt
// to match & call routes _before_ continuing
// on, at which point we assume it's a 404 because
// no route has handled the request.
app.get('/', function(req, res){
res.render('index.ejs');
});
app.use(app.router);
app.get('/404', function(req, res, next){
// trigger a 404 since no other middleware
// will match /404 after this one, and we're not
// responding here
next();
});
app.get('/403', function(req, res, next){
// trigger a 403 error
var err = new Error('not allowed!');
err.status = 403;
next(err);
});
app.get('/500', function(req, res, next){
// trigger a generic (500) error
next(new Error('keyboard cat!'));
});
// Error handlers
// Since this is the last non-error-handling
// middleware use()d, we assume 404, as nothing else
@@ -44,7 +59,7 @@ app.use(app.router);
app.use(function(req, res, next){
res.status(404);
// respond with html page
if (req.accepts('html')) {
res.render('404', { url: req.url });
@@ -81,32 +96,8 @@ app.use(function(err, req, res, next){
res.render('500', { error: err });
});
// Routes
app.get('/', function(req, res){
res.render('index.jade');
});
app.get('/404', function(req, res, next){
// trigger a 404 since no other middleware
// will match /404 after this one, and we're not
// responding here
next();
});
app.get('/403', function(req, res, next){
// trigger a 403 error
var err = new Error('not allowed!');
err.status = 403;
next(err);
});
app.get('/500', function(req, res, next){
// trigger a generic (500) error
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');
}

View File

@@ -0,0 +1,3 @@
<% include error_header %>
<h2>Cannot find <%= url %></h2>
<% include footer %>

View File

@@ -1,5 +0,0 @@
extends error
block content
h2 Cannot find #{url}

View File

@@ -0,0 +1,8 @@
<% include error_header %>
<h2>Error: <%= error.message %></h2>
<% if (settings['verbose errors']) { %>
<pre><%= error.stack %></pre>
<% } else { %>
<p>An error occurred!</p>
<% } %>
<% include footer %>

View File

@@ -1,13 +0,0 @@
// note that we extend a different
// layout with jade for 4xx & 5xx
// responses
extends error
block content
h1 Error: #{error.message}
if settings['verbose errors']
pre= error.stack
else
p An error ocurred!

View File

@@ -1,6 +0,0 @@
html
head
title Error
body
h1 An error occurred!
block content

View File

@@ -0,0 +1,8 @@
<!DOCTYPE html>
<html>
<head>
<title>Error</title>
</head>
<body>
<h1>An error occurred!</h1>

View File

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

View File

@@ -0,0 +1,18 @@
<!DOCTYPE html>
<html>
<head>
<title>Custom Pages Example</title>
</head>
<body>
<h1>My Site</h1>
<h2>Pages Example</h2>
<ul>
<li>visit <a href="/500">500</a></li>
<li>visit <a href="/404">404</a></li>
<li>visit <a href="/403">403</a></li>
</ul>
</body>
</html>

View File

@@ -1,15 +0,0 @@
extends layout
block content
h2 Pages Example
ul
li
| visit
a(href="/500") 500
li
| visit
a(href="/404") 404
li
| visit
a(href='/403') 403

View File

@@ -1,6 +0,0 @@
html
head
title Custom Pages Example
body
h1 My Site
block content

View File

@@ -1,20 +1,13 @@
/**
* Module dependencies.
*/
var express = require('../../')
, app = module.exports = express()
, test = app.get('env') == 'test';
var express = require('../../');
var logger = require('morgan');
var app = module.exports = express();
var test = app.get('env') == 'test';
if (!test) app.use(express.logger('dev'));
app.use(app.router);
// the error handler is strategically
// placed *below* the app.router; if it
// were above it would not receive errors
// from app.get() etc
app.use(error);
if (!test) app.use(logger('dev'));
// error handling middleware have an arity of 4
// instead of the typical (req, res, next),
@@ -27,7 +20,8 @@ function error(err, req, res, next) {
if (!test) console.error(err.stack);
// respond with 500 "Internal Server Error".
res.send(500);
res.status(500);
res.send('Internal Server Error');
}
app.get('/', function(req, res){
@@ -42,7 +36,13 @@ app.get('/next', function(req, res, next){
});
});
// the error handler is placed after routes
// if it were above it would not receive errors
// from app.get() etc
app.use(error);
/* istanbul ignore next */
if (!module.parent) {
app.listen(3000);
console.log('Express started on port 3000');
}
}

View File

@@ -1,6 +1,7 @@
var express = require('../..')
, app = express();
var express = require('../..');
var logger = require('morgan');
var app = express();
app.set('view engine', 'jade');
app.set('views', __dirname + '/views');
@@ -20,10 +21,10 @@ User.prototype.toJSON = function(){
return {
id: this.id,
name: this.name
}
};
};
app.use(express.logger('dev'));
app.use(logger('dev'));
// earlier on expose an object
// that we can tack properties on.
@@ -56,5 +57,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');
}

View File

@@ -1,4 +1,3 @@
var express = require('../../');
var app = express();
@@ -7,5 +6,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');
}

View File

@@ -1,4 +1,3 @@
/**
* Module dependencies.
*/
@@ -12,9 +11,7 @@ var pub = __dirname + '/public';
// setup middleware
var app = express();
app.use(app.router);
app.use(express.static(pub));
app.use(express.errorHandler());
// Optional since express defaults to CWD/views
@@ -41,5 +38,14 @@ app.get('/', function(req, res){
res.render('users', { users: users });
});
app.listen(3000);
console.log('Express app started on port 3000');
// change this to a better error handler in your code
// sending stacktrace to users in production is not good
app.use(function(err, req, res, next) {
res.send(err.stack);
});
/* istanbul ignore next */
if (!module.parent) {
app.listen(3000);
console.log('Express started on port 3000');
}

View File

@@ -1,11 +1,10 @@
/**
* Module dependencies.
*/
var express = require('../..')
, fs = require('fs')
, md = require('marked').parse;
var express = require('../..');
var fs = require('fs');
var md = require('marked').parse;
var app = module.exports = express();
@@ -18,13 +17,13 @@ app.engine('md', function(path, options, fn){
var html = md(str);
html = html.replace(/\{([^}]+)\}/g, function(_, name){
return options[name] || '';
})
});
fn(null, html);
} catch(err) {
fn(err);
}
});
})
});
app.set('views', __dirname + '/views');
@@ -33,12 +32,13 @@ app.set('view engine', 'md');
app.get('/', function(req, res){
res.render('index', { title: 'Markdown Example' });
})
});
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');

View File

@@ -0,0 +1,13 @@
var express = require('../../..');
var apiv1 = express.Router();
apiv1.get('/', function(req, res) {
res.send('Hello from APIv1 root route.');
});
apiv1.get('/users', function(req, res) {
res.send('List of APIv1 users.');
});
module.exports = apiv1;

View File

@@ -0,0 +1,13 @@
var express = require('../../..');
var apiv2 = express.Router();
apiv2.get('/', function(req, res) {
res.send('Hello from APIv2 root route.');
});
apiv2.get('/users', function(req, res) {
res.send('List of APIv2 users.');
});
module.exports = apiv2;

View File

@@ -0,0 +1,16 @@
var express = require('../..');
var app = module.exports = express();
app.use('/api/v1', require('./controllers/api_v1'));
app.use('/api/v2', require('./controllers/api_v2'));
app.get('/', function(req, res) {
res.send('Hello form root route.');
});
/* istanbul ignore next */
if (!module.parent) {
app.listen(3000);
console.log('Express started on port 3000');
}

View File

@@ -1,16 +1,12 @@
/**
* Module dependencies.
*/
var express = require('../..')
, format = require('util').format;
var express = require('../..');
var multiparty = require('multiparty');
var format = require('util').format;
var app = module.exports = express()
// bodyParser in connect 2.x uses node-formidable to parse
// the multipart form data.
app.use(express.bodyParser())
var app = module.exports = express();
app.get('/', function(req, res){
res.send('<form method="post" enctype="multipart/form-data">'
@@ -21,16 +17,44 @@ app.get('/', function(req, res){
});
app.post('/', function(req, res, next){
// the uploaded file can be found as `req.files.image` and the
// title field as `req.body.title`
res.send(format('\nuploaded %s (%d Kb) to %s as %s'
, req.files.image.name
, req.files.image.size / 1024 | 0
, req.files.image.path
, req.body.title));
// create a form to begin parsing
var form = new multiparty.Form();
var image;
var title;
form.on('error', next);
form.on('close', function(){
res.send(format('\nuploaded %s (%d Kb) as %s'
, image.filename
, image.size / 1024 | 0
, title));
});
// listen on field event for title
form.on('field', function(name, val){
if (name !== 'title') return;
title = val;
});
// listen on part event for image file
form.on('part', function(part){
if (!part.filename) return;
if (part.name !== 'image') return part.resume();
image = {};
image.filename = part.filename;
image.size = 0;
part.on('data', function(buf){
image.size += buf.length;
});
});
// parse the form
form.parse(req);
});
/* istanbul ignore next */
if (!module.parent) {
app.listen(3000);
console.log('Express started on port 3000');
}
app.listen(4000);
console.log('Express started on port 4000');
}

View File

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

View File

@@ -1,11 +1,14 @@
/**
* Module dependencies.
*/
var db = require('../../db');
exports.engine = 'jade';
exports.engine = 'ejs';
exports.before = function(req, res, next){
var pet = db.pets[req.params.pet_id];
if (!pet) return next(new Error('Pet not found'));
if (!pet) return next('route');
req.pet = pet;
next();
};
@@ -20,7 +23,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);
};

View File

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

View File

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

View File

@@ -0,0 +1,13 @@
<!DOCTYPE html>
<html>
<head>
<link rel="stylesheet" href="/style.css">
<title><%= pet.name %></title>
</head>
<body>
<h1><%= pet.name %> <a href="/pet/<%= pet.id %>/edit">edit</a></h1>
<p>You are viewing <%= pet.name %></p>
</body>
</html>

View File

@@ -1,6 +0,0 @@
link(rel='stylesheet', href='/style.css')
h1= pet.name
a(href='/pet/#{pet.id}/edit') edit
p You are viewing #{pet.name}

View File

@@ -1,3 +1,6 @@
/**
* Module dependencies.
*/
var db = require('../../db');
@@ -8,7 +11,7 @@ exports.create = function(req, res, next){
var id = req.params.user_id;
var user = db.users[id];
var body = req.body;
if (!user) return next(new Error('User not found'));
if (!user) return next('route');
var pet = { name: body.pet.name };
pet.id = db.pets.push(pet) - 1;
user.pets.push(pet);

View File

@@ -1,3 +1,6 @@
/**
* Module dependencies.
*/
var db = require('../../db');
@@ -8,11 +11,11 @@ exports.before = function(req, res, next){
process.nextTick(function(){
req.user = db.users[id];
// cant find that user
if (!req.user) return next(new Error('User not found'));
if (!req.user) return next('route');
// found it, move on to the routes
next();
});
}
};
exports.list = function(req, res, next){
res.render('list', { users: db.users });

View File

@@ -1,12 +0,0 @@
<link rel="stylesheet" href="/style.css" />
<h1><%= user.name %></h1>
<form action='/user/<%= user.id %>' method='post'>
<input type="hidden" name="_method" value="put" />
<label>Name: <input type="text" name="user[name]" value="<%= user.name %>" /></label>
<input type="submit" value="Update" />
</form>
<form action='/user/<%= user.id %>/pet' method='post'>
<label>Pet: <input type="text" name="pet[name]" placeholder="name" /></label>
<input type="submit" value="Add" />
</form>

View File

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

View File

@@ -1,8 +0,0 @@
<link rel="stylesheet" href="/style.css" />
<h1>Users</h1>
<p>Click a user below to view their pets.</p>
<ul>
<% users.forEach(function(user){ %>
<li><a href="/user/<%= user.id %>"><%= user.name %></a></li>
<% }) %>
</ul>

View File

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

View File

@@ -1,21 +0,0 @@
<link rel="stylesheet" href="/style.css" />
<h1><%= user.name %> <a href="/user/<%= user.id %>/edit">edit</a></h1>
<% if (hasMessages) { %>
<ul id="messages">
<% messages.forEach(function(msg){ %>
<li><%= msg %></li>
<% }) %>
</ul>
<% } %>
<% if (user.pets.length) { %>
<p>View <%= user.name %>s pets:</p>
<ul>
<% user.pets.forEach(function(pet){ %>
<li><a href="/pet/<%= pet.id %>"><%= pet.name %></a></li>
<% }) %>
</ul>
<% } else { %>
<p>No pets!</p>
<% } %>

View File

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

View File

@@ -1,4 +1,3 @@
// faux database
var pets = exports.pets = [];

View File

@@ -1,14 +1,20 @@
/**
* Module dependencies.
*/
var express = require('../..');
var logger = require('morgan');
var session = require('express-session');
var bodyParser = require('body-parser');
var methodOverride = require('method-override');
var app = module.exports = express();
// settings
// map .renderFile to ".html" files
app.engine('html', require('ejs').renderFile);
// make ".html" the default
app.set('view engine', 'html');
// set our default template engine to "jade"
// which prevents the need for extensions
app.set('view engine', 'jade');
// set views for error and 404 pages
app.set('views', __dirname + '/views');
@@ -25,20 +31,23 @@ app.response.message = function(msg){
};
// log
if (!module.parent) app.use(express.logger('dev'));
if (!module.parent) app.use(logger('dev'));
// serve static files
app.use(express.static(__dirname + '/public'));
// session support
app.use(express.cookieParser('some secret here'));
app.use(express.session());
app.use(session({
resave: false, // don't save session if unmodified
saveUninitialized: false, // don't create session until something stored
secret: 'some secret here'
}));
// parse request bodies (req.body)
app.use(express.bodyParser());
app.use(bodyParser.urlencoded({ extended: true }));
// support _method (PUT in forms etc)
app.use(express.methodOverride());
// allow overriding methods in query (?_method=put)
app.use(methodOverride('_method'));
// expose the "messages" local variable when views are rendered
app.use(function(req, res, next){
@@ -66,16 +75,9 @@ app.use(function(req, res, next){
// load controllers
require('./lib/boot')(app, { verbose: !module.parent });
// assume "not found" in the error msgs
// is a 404. this is somewhat silly, but
// valid, you can do whatever you like, set
// properties, use instanceof etc.
app.use(function(err, req, res, next){
// treat as 404
if (~err.message.indexOf('not found')) return next();
// log it
console.error(err.stack);
if (!module.parent) console.error(err.stack);
// error page
res.status(500).render('5xx');
@@ -86,7 +88,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');
}

View File

@@ -1,32 +1,26 @@
/**
* Module dependencies.
*/
var express = require('../../..')
, fs = require('fs');
var express = require('../../..');
var fs = require('fs');
module.exports = function(parent, options){
var verbose = options.verbose;
fs.readdirSync(__dirname + '/../controllers').forEach(function(name){
verbose && console.log('\n %s:', name);
var obj = require('./../controllers/' + name)
, name = obj.name || name
, prefix = obj.prefix || ''
, app = express()
, method
, path;
var obj = require('./../controllers/' + name);
var name = obj.name || name;
var prefix = obj.prefix || '';
var app = express();
var handler;
var method;
var path;
// allow specifying the view engine
if (obj.engine) app.set('view engine', obj.engine);
app.set('views', __dirname + '/../controllers/' + name + '/views');
// before middleware support
if (obj.before) {
path = '/' + name + '/:' + name + '_id';
app.all(path, obj.before);
verbose && console.log(' ALL %s -> before', path);
path = '/' + name + '/:' + name + '_id/*';
app.all(path, obj.before);
verbose && console.log(' ALL %s -> before', path);
}
// generate routes based
// on the exported methods
for (var key in obj) {
@@ -59,15 +53,25 @@ module.exports = function(parent, options){
path = '/';
break;
default:
/* istanbul ignore next */
throw new Error('unrecognized route: ' + name + '.' + key);
}
// setup
handler = obj[key];
path = prefix + path;
app[method](path, obj[key]);
verbose && console.log(' %s %s -> %s', method.toUpperCase(), path, key);
// before middleware support
if (obj.before) {
app[method](path, obj.before, handler);
verbose && console.log(' %s %s -> before -> %s', method.toUpperCase(), path, key);
} else {
app[method](path, obj[key]);
verbose && console.log(' %s %s -> %s', method.toUpperCase(), path, key);
}
}
// mount the app
parent.use(app);
});
};
};

View File

@@ -1,3 +0,0 @@
<link rel="stylesheet" href="/style.css" />
<h1>404: Not Found</h1>
<p>Sorry we can't find <%= url %></p>

View File

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

View File

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

View File

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

View File

@@ -1,4 +1,3 @@
// first:
// $ npm install redis online
// $ redis-server
@@ -7,10 +6,10 @@
* Module dependencies.
*/
var express = require('../..')
, online = require('online')
, redis = require('redis')
, db = redis.createClient();
var express = require('../..');
var online = require('online');
var redis = require('redis');
var db = redis.createClient();
// online
@@ -50,5 +49,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');
}

View File

@@ -1,10 +1,9 @@
/**
* Module dependencies.
*/
var express = require('../../')
, app = module.exports = express();
var express = require('../../');
var app = module.exports = express();
// Faux database
@@ -18,9 +17,9 @@ 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) ){
app.param(['to', 'from'], function(req, res, next, num, name){
req.params[name] = parseInt(num, 10);
if( isNaN(req.params[name]) ){
next(new Error('failed to parseInt '+num));
} else {
next();
@@ -58,13 +57,14 @@ app.get('/user/:user', function(req, res, next){
*/
app.get('/users/:from-:to', function(req, res, next){
var from = req.params.from
, to = req.params.to
, names = users.map(function(user){ return user.name; });
var from = req.params.from;
var to = req.params.to;
var names = users.map(function(user){ return user.name; });
res.send('users ' + names.slice(from, to).join(', '));
});
/* istanbul ignore next */
if (!module.parent) {
app.listen(3000);
console.log('Express started on port 3000');
}
}

View File

@@ -1,4 +1,3 @@
/**
* Module dependencies.
*/
@@ -12,13 +11,16 @@ var app = module.exports = express();
app.resource = function(path, obj) {
this.get(path, obj.index);
this.get(path + '/:a..:b.:format?', function(req, res){
var a = parseInt(req.params.a, 10)
, b = parseInt(req.params.b, 10)
, format = req.params.format;
var a = parseInt(req.params.a, 10);
var b = parseInt(req.params.b, 10);
var format = req.params.format;
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 +43,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');
@@ -82,10 +83,11 @@ app.get('/', function(req, res){
, '<li>GET /users/1..3.json</li>'
, '<li>DELETE /users/4</li>'
, '</ul>'
].join('\n'));
].join('\n'));
});
/* istanbul ignore next */
if (!module.parent) {
app.listen(3000);
console.log('Express started on port 3000');
}
}

View File

@@ -1,7 +1,12 @@
/**
* Module dependencies.
*/
var express = require('../../lib/express')
, verbose = process.env.NODE_ENV != 'test'
, app = module.exports = express();
var express = require('../../lib/express');
var verbose = process.env.NODE_ENV != 'test';
var app = module.exports = express();
app.map = function(a, route){
route = route || '';
@@ -29,7 +34,7 @@ var users = {
res.send('user ' + req.params.uid);
},
del: function(req, res){
delete: function(req, res){
res.send('delete users');
}
};
@@ -39,7 +44,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 +52,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');
}

View File

@@ -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');
}

View File

@@ -1,22 +1,32 @@
/**
* Module dependencies.
*/
var express = require('../..')
, app = express()
, site = require('./site')
, post = require('./post')
, user = require('./user');
var express = require('../..');
var app = express();
var logger = require('morgan');
var cookieParser = require('cookie-parser');
var bodyParser = require('body-parser');
var methodOverride = require('method-override');
var site = require('./site');
var post = require('./post');
var user = require('./user');
module.exports = app;
// Config
app.set('view engine', 'jade');
app.set('views', __dirname + '/views');
app.use(express.logger('dev'));
app.use(express.cookieParser());
app.use(express.bodyParser());
app.use(express.methodOverride());
/* istanbul ignore next */
if (!module.parent) {
app.use(express.logger('dev'));
}
app.use(methodOverride('_method'));
app.use(cookieParser());
app.use(bodyParser.urlencoded({ extended: true }));
app.use(express.static(__dirname + '/public'));
// General
@@ -25,7 +35,7 @@ app.get('/', site.index);
// User
app.all('/users', user.list);
app.get('/users', user.list);
app.all('/user/:id/:op?', user.load);
app.get('/user/:id', user.view);
app.get('/user/:id/view', user.view);
@@ -36,5 +46,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');
}

View File

@@ -1,4 +1,3 @@
// Fake posts database
var posts = [

View File

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

View File

@@ -1,4 +1,3 @@
// Fake user database
var users = [
@@ -16,7 +15,9 @@ exports.load = function(req, res, next){
if (req.user) {
next();
} else {
next(new Error('cannot find user ' + id));
var err = new Error('cannot find user ' + id);
err.status = 404;
next(err);
}
};
@@ -41,4 +42,4 @@ exports.update = function(req, res){
req.user.name = user.name;
req.user.email = user.email;
res.redirect('back');
};
};

View File

@@ -3,8 +3,7 @@ extends ../layout
block content
h1 Editing #{user.name}
#user
form(method="post")
input(type="hidden", value="put", name="_method")
form(action="?_method=put", method="post")
p Name:
input(type="text", value= user.name, name="user[name]")
p Email:

View File

@@ -1,4 +1,3 @@
var search = document.querySelector('[type=search]');
var code = document.querySelector('pre');

View File

@@ -1,4 +1,3 @@
// first:
// $ npm install redis
// $ redis-server
@@ -7,9 +6,10 @@
* Module dependencies.
*/
var express = require('../..')
, redis = require('redis')
, db = redis.createClient();
var express = require('../..');
var redis = require('redis');
var db = redis.createClient();
// npm install redis
@@ -47,15 +47,18 @@ app.get('/search/:query?', function(req, res){
});
/**
* GET client javascript. Here we use sendfile()
* GET client javascript. Here we use sendFile()
* because serving __dirname with the static() middleware
* would also mean serving our server "index.js" and the "search.jade"
* template.
*/
app.get('/client.js', function(req, res){
res.sendfile(__dirname + '/client.js');
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');
}

View File

@@ -1,4 +1,4 @@
!!! 5
doctype
html
head
title Search example

View File

@@ -1,21 +1,18 @@
// first:
// $ npm install redis
// $ redis-server
var express = require('../..');
var session = require('express-session');
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(session({
resave: false, // don't save session if unmodified
saveUninitialized: false, // don't create session until something stored
secret: 'keyboard cat'
}));
app.get('/', function(req, res){
var body = '';
@@ -28,5 +25,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');
}

View File

@@ -1,22 +1,26 @@
/**
* Module dependencies.
*/
var express = require('../..');
var logger = require('morgan');
var session = require('express-session');
// pass the express to the connect redis module
// allowing it to inherit from express.session.Store
var RedisStore = require('connect-redis')(express);
// allowing it to inherit from session.Store
var RedisStore = require('connect-redis')(session);
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'));
app.use(logger('dev'));
// Populates req.session
app.use(express.session({ store: new RedisStore }));
app.use(session({
resave: false, // don't save session if unmodified
saveUninitialized: false, // don't create session until something stored
secret: 'keyboard cat',
store: new RedisStore
}));
app.get('/', function(req, res){
var body = '';

View File

@@ -1,9 +1,13 @@
/**
* Module dependencies.
*/
var express = require('../..');
var logger = require('morgan');
var app = express();
// log requests
app.use(express.logger('dev'));
app.use(logger('dev'));
// express on its own has no notion
// of a "file". The express.static()
@@ -28,17 +32,9 @@ app.use('/static', express.static(__dirname + '/public'));
// this will allow "GET /style.css" instead of "GET /css/style.css":
app.use(express.static(__dirname + '/public/css'));
// this examples does not have any routes, however
// you may `app.use(app.router)` before or after these
// static() middleware. If placed before them your routes
// will be matched BEFORE file serving takes place. If placed
// after as shown here then file serving is performed BEFORE
// any routes are hit:
app.use(app.router);
app.listen(3000);
console.log('listening on port 3000');
console.log('try:');
console.log(' GET /hello.txt');
console.log(' GET /js/app.js');
console.log(' GET /css/style.css');
console.log(' GET /css/style.css');

View File

@@ -3,6 +3,8 @@
*/
var express = require('../..');
var logger = require('morgan');
var vhost = require('vhost');
/*
edit /etc/hosts:
@@ -16,10 +18,10 @@ edit /etc/hosts:
var main = express();
main.use(express.logger('dev'));
if (!module.parent) main.use(logger('dev'));
main.get('/', function(req, res){
res.send('Hello from main app!')
res.send('Hello from main app!');
});
main.get('/:sub', function(req, res){
@@ -30,17 +32,20 @@ main.get('/:sub', function(req, res){
var redirect = express();
redirect.all('*', function(req, res){
console.log(req.subdomains);
res.redirect('http://example.com:3000/' + req.subdomains[0]);
redirect.use(function(req, res){
if (!module.parent) console.log(req.vhost);
res.redirect('http://example.com:3000/' + req.vhost[0]);
});
// Vhost app
var app = express();
var app = module.exports = express();
app.use(express.vhost('*.example.com', redirect)) // Serves all subdomains via Redirect app
app.use(express.vhost('example.com', main)); // Serves top level domain via Main server app
app.use(vhost('*.example.com', redirect)); // Serves all subdomains via Redirect app
app.use(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');
}

View File

@@ -1,11 +1,10 @@
/**
* Module dependencies.
*/
var http = require('http')
, path = require('path')
, extname = path.extname
var http = require('http');
var path = require('path');
var extname = path.extname;
/**
* Expose `GithubView`.
@@ -35,13 +34,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 });

View File

@@ -1,12 +1,11 @@
/**
* Module dependencies.
*/
var express = require('../../')
, http = require('http')
, GithubView = require('./github-view')
, md = require('marked').parse;
var express = require('../../');
var http = require('http');
var GithubView = require('./github-view');
var md = require('marked').parse;
var app = module.exports = express();
@@ -16,15 +15,15 @@ app.engine('md', function(str, options, fn){
var html = md(str);
html = html.replace(/\{([^}]+)\}/g, function(_, name){
return options[name] || '';
})
});
fn(null, html);
} catch(err) {
fn(err);
}
})
});
// 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);
@@ -34,13 +33,14 @@ app.get('/', function(req, res){
// app.locals, res.locals, and locals passed
// work like they normally would
res.render('examples/markdown/views/index.md', { title: 'Example' });
})
});
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');

View File

@@ -1,7 +1,10 @@
/**
* Module dependencies.
*/
var express = require('../..')
, User = require('./user')
, app = express();
var express = require('../..');
var User = require('./user');
var app = express();
app.set('views', __dirname);
app.set('view engine', 'jade');
@@ -69,7 +72,7 @@ app.get('/middleware', count, users, function(req, res, next){
// this approach is much like the last
// however we're explicitly exposing
// the locals within each middleware
//
//
// note that this may not always work
// well, for example here we filter
// the users in the middleware, which
@@ -142,5 +145,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');
}

View File

@@ -1,4 +1,3 @@
module.exports = User;
// faux model

View File

@@ -1,4 +1,3 @@
/**
* Module dependencies.
*/
@@ -29,7 +28,7 @@ function error(status, msg) {
app.use('/api', function(req, res, next){
var key = req.query['api-key'];
// key isnt present
// key isn't present
if (!key) return next(error(400, 'api key required'));
// key is invalid
@@ -40,29 +39,6 @@ app.use('/api', function(req, res, next){
next();
});
// position our routes above the error handling middleware,
// and below our API middleware, since we want the API validation
// to take place BEFORE our routes
app.use(app.router);
// middleware with an arity of 4 are considered
// error handling middleware. When you next(err)
// it will be passed through the defined middleware
// in order, but ONLY those with an arity of 4, ignoring
// regular middleware.
app.use(function(err, req, res, next){
// whatever you want here, feel free to populate
// properties on `err` to treat it differently in here.
res.send(err.status || 500, { error: err.message });
});
// our custom JSON 404 middleware. Since it's placed last
// it will be the last middleware called, if all others
// invoke next() and do not respond.
app.use(function(req, res){
res.send(404, { error: "Lame, can't find that" });
});
// map of valid api keys, typically mapped to
// account info with some sort of database like redis.
// api keys do _not_ serve as authentication, merely to
@@ -73,7 +49,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' }
];
@@ -102,14 +78,35 @@ app.get('/api/repos', function(req, res, next){
});
app.get('/api/user/:name/repos', function(req, res, next){
var name = req.params.name
, user = userRepos[name];
var name = req.params.name;
var user = userRepos[name];
if (user) res.send(user);
else next();
});
// middleware with an arity of 4 are considered
// error handling middleware. When you next(err)
// it will be passed through the defined middleware
// in order, but ONLY those with an arity of 4, ignoring
// regular middleware.
app.use(function(err, req, res, next){
// whatever you want here, feel free to populate
// properties on `err` to treat it differently in here.
res.status(err.status || 500);
res.send({ error: err.message });
});
// our custom JSON 404 middleware. Since it's placed last
// it will be the last middleware called, if all others
// invoke next() and do not respond.
app.use(function(req, res){
res.status(404);
res.send({ error: "Lame, can't find that" });
});
/* istanbul ignore next */
if (!module.parent) {
app.listen(3000);
console.log('Express server listening on port 3000');
}
console.log('Express started on port 3000');
}

View File

@@ -1,4 +1,2 @@
module.exports = process.env.EXPRESS_COV
? require('./lib-cov/express')
: require('./lib/express');
module.exports = require('./lib/express');

View File

@@ -2,15 +2,22 @@
* Module dependencies.
*/
var connect = require('connect')
, Router = require('./router')
, methods = require('methods')
, middleware = require('./middleware')
, debug = require('debug')('express:application')
, locals = require('./utils').locals
, View = require('./view')
, utils = connect.utils
, http = require('http');
var finalhandler = require('finalhandler');
var flatten = require('./utils').flatten;
var Router = require('./router');
var methods = require('methods');
var middleware = require('./middleware/init');
var query = require('./middleware/query');
var debug = require('debug')('express:application');
var View = require('./view');
var http = require('http');
var compileETag = require('./utils').compileETag;
var compileQueryParser = require('./utils').compileQueryParser;
var compileTrust = require('./utils').compileTrust;
var deprecate = require('depd')('express');
var merge = require('utils-merge');
var resolve = require('path').resolve;
var slice = Array.prototype.slice;
/**
* Application prototype.
@@ -44,14 +51,14 @@ app.init = function(){
app.defaultConfiguration = function(){
// default settings
this.enable('x-powered-by');
this.enable('etag');
this.set('env', process.env.NODE_ENV || 'development');
this.set('etag', 'weak');
var env = process.env.NODE_ENV || 'development';
this.set('env', env);
this.set('query parser', 'extended');
this.set('subdomain offset', 2);
debug('booting in %s mode', this.get('env'));
this.set('trust proxy', false);
// implicit middleware
this.use(connect.query());
this.use(middleware.init(this));
debug('booting in %s mode', env);
// inherit protos
this.on('mount', function(parent){
@@ -61,79 +68,161 @@ app.defaultConfiguration = function(){
this.settings.__proto__ = parent.settings;
});
// router
this._router = new Router(this);
this.routes = this._router.map;
this.__defineGetter__('router', function(){
this._usedRouter = true;
this._router.caseSensitive = this.enabled('case sensitive routing');
this._router.strict = this.enabled('strict routing');
return this._router.middleware;
});
// setup locals
this.locals = locals(this);
this.locals = Object.create(null);
// top-most app is mounted at /
this.mountpath = '/';
// default locals
this.locals.settings = this.settings;
// default configuration
this.set('view', View);
this.set('views', process.cwd() + '/views');
this.set('views', resolve('views'));
this.set('jsonp callback name', 'callback');
this.configure('development', function(){
this.set('json spaces', 2);
});
this.configure('production', function(){
if (env === 'production') {
this.enable('view cache');
}
Object.defineProperty(this, 'router', {
get: function() {
throw new Error('\'app.router\' is deprecated!\nPlease see the 3.x to 4.x migration guide for details on how to update your app.');
}
});
};
/**
* Proxy `connect#use()` to apply settings to
* mounted applications.
* lazily adds the base router if it has not yet been added.
*
* We cannot add the base router in the defaultConfiguration because
* it reads app settings which might be set after that has run.
*
* @api private
*/
app.lazyrouter = function() {
if (!this._router) {
this._router = new Router({
caseSensitive: this.enabled('case sensitive routing'),
strict: this.enabled('strict routing')
});
this._router.use(query(this.get('query parser fn')));
this._router.use(middleware.init(this));
}
};
/**
* Dispatch a req, res pair into the application. Starts pipeline processing.
*
* If no _done_ callback is provided, then default error handlers will respond
* in the event of an error bubbling through the stack.
*
* @api private
*/
app.handle = function(req, res, done) {
var router = this._router;
// final handler
done = done || finalhandler(req, res, {
env: this.get('env'),
onerror: logerror.bind(this)
});
// no routes
if (!router) {
debug('no routes defined on app');
done();
return;
}
router.handle(req, res, done);
};
/**
* Proxy `Router#use()` to add middleware to the app router.
* See Router#use() documentation for details.
*
* If the _fn_ parameter is an express app, then it will be
* mounted at the _route_ specified.
*
* @param {String|Function|Server} route
* @param {Function|Server} fn
* @return {app} for chaining
* @api public
*/
app.use = function(route, fn){
var app;
app.use = function use(fn) {
var offset = 0;
var path = '/';
// default route to '/'
if ('string' != typeof route) fn = route, route = '/';
// default path to '/'
// disambiguate app.use([fn])
if (typeof fn !== 'function') {
var arg = fn;
// express app
if (fn.handle && fn.set) app = fn;
while (Array.isArray(arg) && arg.length !== 0) {
arg = arg[0];
}
// restore .app property on req and res
if (app) {
app.route = route;
fn = function(req, res, next) {
// first arg is the path
if (typeof arg !== 'function') {
offset = 1;
path = fn;
}
}
var fns = flatten(slice.call(arguments, offset));
if (fns.length === 0) {
throw new TypeError('app.use() requires middleware functions');
}
// setup router
this.lazyrouter();
var router = this._router;
fns.forEach(function (fn) {
// non-express app
if (!fn || !fn.handle || !fn.set) {
return router.use(path, fn);
}
debug('.use app under %s', path);
fn.mountpath = path;
fn.parent = this;
// restore .app property on req and res
router.use(path, function mounted_app(req, res, next) {
var orig = req.app;
app.handle(req, res, function(err){
fn.handle(req, res, function (err) {
req.__proto__ = orig.request;
res.__proto__ = orig.response;
next(err);
});
};
}
});
connect.proto.use.call(this, route, fn);
// mounted an app
if (app) {
app.parent = this;
app.emit('mount', this);
}
// mounted an app
fn.emit('mount', this);
}, this);
return this;
};
/**
* Proxy to the app `Router#route()`
* Returns a new `Route` instance for the _path_.
*
* Routes are isolated middleware stacks for specific paths.
* See the Route api docs for details.
*
* @api public
*/
app.route = function(path){
this.lazyrouter();
return this._router.route(path);
};
/**
* Register the given template engine callback `fn`
* as `ext`.
@@ -157,7 +246,7 @@ app.use = function(route, fn){
* so if you're using ".ejs" extensions you dont need to do anything.
*
* Some template engines do not follow this convention, the
* [Consolidate.js](https://github.com/visionmedia/consolidate.js)
* [Consolidate.js](https://github.com/tj/consolidate.js)
* library was created to map all of node's popular template
* engines to follow this convention, thus allowing them to
* work seamlessly within Express.
@@ -176,30 +265,10 @@ app.engine = function(ext, fn){
};
/**
* Map the given param placeholder `name`(s) to the given callback(s).
* Proxy to `Router#param()` with one added api feature. The _name_ parameter
* can be an array of names.
*
* Parameter mapping is used to provide pre-conditions to routes
* which use normalized placeholders. For example a _:user_id_ parameter
* could automatically load a user's information from the database without
* any additional code,
*
* The callback uses the same signature as middleware, the only difference
* being that the value of the placeholder is passed, in this case the _id_
* of the user. Once the `next()` function is invoked, just like middleware
* it will continue on to execute the route, or subsequent parameter functions.
*
* app.param('user_id', function(req, res, next, id){
* User.find(id, function(err, user){
* if (err) {
* next(err);
* } else if (user) {
* req.user = user;
* next();
* } else {
* next(new Error('failed to load user'));
* }
* });
* });
* See the Router#param() docs for more details.
*
* @param {String|Array} name
* @param {Function} fn
@@ -208,27 +277,16 @@ app.engine = function(ext, fn){
*/
app.param = function(name, fn){
var self = this
, fns = [].slice.call(arguments, 1);
this.lazyrouter();
// array
if (Array.isArray(name)) {
name.forEach(function(name){
fns.forEach(function(fn){
self.param(name, fn);
});
});
// param logic
} else if ('function' == typeof name) {
this._router.param(name);
// single
} else {
if (':' == name[0]) name = name.substr(1);
fns.forEach(function(fn){
self._router.param(name, fn);
});
name.forEach(function(key) {
this.param(key, fn);
}, this);
return this;
}
this._router.param(name, fn);
return this;
};
@@ -242,18 +300,37 @@ 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 'query parser':
debug('compile query parser %s', val);
this.set('query parser fn', compileQueryParser(val));
break;
case 'trust proxy':
debug('compile trust proxy %s', val);
this.set('trust proxy fn', compileTrust(val));
break;
}
return this;
};
/**
@@ -272,7 +349,7 @@ app.set = function(setting, val){
app.path = function(){
return this.parent
? this.parent.path() + this.route
? this.parent.path() + this.mountpath
: '';
};
@@ -338,60 +415,6 @@ app.disable = function(setting){
return this.set(setting, false);
};
/**
* Configure callback for zero or more envs,
* when no `env` is specified that callback will
* be invoked for all environments. Any combination
* can be used multiple times, in any order desired.
*
* Examples:
*
* app.configure(function(){
* // executed for all envs
* });
*
* app.configure('stage', function(){
* // executed staging env
* });
*
* app.configure('stage', 'production', function(){
* // executed for stage and production
* });
*
* Note:
*
* These callbacks are invoked immediately, and
* are effectively sugar for the following:
*
* var env = process.env.NODE_ENV || 'development';
*
* switch (env) {
* case 'development':
* ...
* break;
* case 'stage':
* ...
* break;
* case 'production':
* ...
* break;
* }
*
* @param {String} env...
* @param {Function} fn
* @return {app} for chaining
* @api public
*/
app.configure = function(env, fn){
var envs = 'all'
, args = [].slice.call(arguments);
fn = args.pop();
if (args.length) envs = args;
if ('all' == envs || ~envs.indexOf(this.settings.env)) fn.call(this);
return this;
};
/**
* Delegate `.VERB(...)` calls to `router.VERB(...)`.
*/
@@ -400,16 +423,10 @@ 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');
}
this.lazyrouter();
// if no router attached yet, attach the router
if (!this._usedRouter) this.use(this.router);
// setup route
this._router[method].apply(this._router, arguments);
var route = this._router.route(path);
route[method].apply(route, slice.call(arguments, 1));
return this;
};
});
@@ -425,16 +442,20 @@ methods.forEach(function(method){
*/
app.all = function(path){
var args = arguments;
this.lazyrouter();
var route = this._router.route(path);
var args = slice.call(arguments, 1);
methods.forEach(function(method){
app[method].apply(this, args);
}, this);
route[method].apply(route, args);
});
return this;
};
// 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`
@@ -454,10 +475,10 @@ app.del = app.delete;
*/
app.render = function(name, options, fn){
var opts = {}
, cache = this.cache
, engines = this.engines
, view;
var opts = {};
var cache = this.cache;
var engines = this.engines;
var view;
// support callback function as second arg
if ('function' == typeof options) {
@@ -465,13 +486,15 @@ app.render = function(name, options, fn){
}
// merge app.locals
utils.merge(opts, this.locals);
merge(opts, this.locals);
// merge options._locals
if (options._locals) utils.merge(opts, options._locals);
if (options._locals) {
merge(opts, options._locals);
}
// merge options
utils.merge(opts, options);
merge(opts, options);
// set .cache unless explicitly provided
opts.cache = null == opts.cache
@@ -490,7 +513,10 @@ app.render = function(name, options, fn){
});
if (!view.path) {
var err = new Error('Failed to lookup view "' + name + '" in views directory "' + view.root + '"');
var dirs = Array.isArray(view.root) && view.root.length > 1
? 'directories "' + view.root.slice(0, -1).join('", "') + '" or "' + view.root[view.root.length - 1] + '"'
: 'directory "' + view.root + '"'
var err = new Error('Failed to lookup view "' + name + '" in views ' + dirs);
err.view = view;
return fn(err);
}
@@ -532,3 +558,14 @@ app.listen = function(){
var server = http.createServer(this);
return server.listen.apply(server, arguments);
};
/**
* Log error using console.error.
*
* @param {Error} err
* @api public
*/
function logerror(err){
if (this.get('env') !== 'test') console.error(err.stack || err.toString());
}

View File

@@ -2,14 +2,13 @@
* Module dependencies.
*/
var merge = require('merge-descriptors');
var connect = require('connect')
, proto = require('./application')
, Route = require('./router/route')
, Router = require('./router')
, req = require('./request')
, res = require('./response')
, utils = connect.utils;
var EventEmitter = require('events').EventEmitter;
var mixin = require('merge-descriptors');
var proto = require('./application');
var Route = require('./router/route');
var Router = require('./router');
var req = require('./request');
var res = require('./response');
/**
* Expose `createApplication()`.
@@ -17,12 +16,6 @@ var connect = require('connect')
exports = module.exports = createApplication;
/**
* Expose mime.
*/
exports.mime = connect.mime;
/**
* Create an express application.
*
@@ -31,36 +24,19 @@ exports.mime = connect.mime;
*/
function createApplication() {
var app = connect();
utils.merge(app, proto);
var app = function(req, res, next) {
app.handle(req, res, next);
};
mixin(app, proto);
mixin(app, EventEmitter.prototype);
app.request = { __proto__: req, app: app };
app.response = { __proto__: res, app: app };
app.init();
return app;
}
/**
* Expose connect.middleware as express.*
* for example `express.logger` etc.
*/
merge(exports, connect.middleware);
/**
* Error on 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();
};
/**
* Expose the prototypes.
*/
@@ -76,7 +52,42 @@ exports.response = res;
exports.Route = Route;
exports.Router = Router;
// Error handler title
/**
* Expose middleware
*/
exports.errorHandler.title = 'Express';
exports.query = require('./middleware/query');
exports.static = require('serve-static');
/**
* Replace removed middleware with an appropriate error message.
*/
[
'json',
'urlencoded',
'bodyParser',
'compress',
'cookieSession',
'session',
'logger',
'cookieParser',
'favicon',
'responseTime',
'errorHandler',
'timeout',
'methodOverride',
'vhost',
'csrf',
'directory',
'limit',
'multipart',
'staticCache',
].forEach(function (name) {
Object.defineProperty(exports, name, {
get: function () {
throw new Error('Most middleware (like ' + name + ') is no longer bundled with Express and must be installed separately. Please see https://github.com/senchalabs/connect#middleware.');
},
configurable: true
});
});

View File

@@ -1,10 +1,3 @@
/**
* Module dependencies.
*/
var utils = require('./utils');
/**
* Initialization middleware, exposing the
* request and response to eachother, as well
@@ -25,8 +18,9 @@ exports.init = function(app){
req.__proto__ = app.request;
res.__proto__ = app.response;
res.locals = res.locals || utils.locals(res);
res.locals = res.locals || Object.create(null);
next();
}
};
};

30
lib/middleware/query.js Normal file
View File

@@ -0,0 +1,30 @@
/**
* Module dependencies.
*/
var parseUrl = require('parseurl');
var qs = require('qs');
/**
* @param {Object} options
* @return {Function}
* @api public
*/
module.exports = function query(options) {
var queryparse = qs.parse;
if (typeof options === 'function') {
queryparse = options;
options = undefined;
}
return function query(req, res, next){
if (!req.query) {
var val = parseUrl(req).query;
req.query = queryparse(val, options);
}
next();
};
};

View File

@@ -1,15 +1,16 @@
/**
* Module dependencies.
*/
var http = require('http')
, utils = require('./utils')
, connect = require('connect')
, fresh = require('fresh')
, parseRange = require('range-parser')
, parse = connect.utils.parseUrl
, mime = connect.mime;
var accepts = require('accepts');
var deprecate = require('depd')('express');
var isIP = require('net').isIP;
var typeis = require('type-is');
var http = require('http');
var fresh = require('fresh');
var parseRange = require('range-parser');
var parse = require('parseurl');
var proxyaddr = require('proxy-addr');
/**
* Request prototype.
@@ -56,6 +57,8 @@ req.header = function(name){
};
/**
* To do: update docs.
*
* Check if the given `type(s)` is acceptable, returning
* the best match when true, otherwise `undefined`, in which
* case you should respond with 406 "Not Acceptable".
@@ -99,55 +102,61 @@ req.header = function(name){
* @api public
*/
req.accepts = function(type){
var args = arguments.length > 1 ? [].slice.apply(arguments) : type;
return utils.accepts(args, this.get('Accept'));
req.accepts = function(){
var accept = accepts(this);
return accept.types.apply(accept, arguments);
};
/**
* Check if the given `encoding` is accepted.
* Check if the given `encoding`s are accepted.
*
* @param {String} encoding
* @param {String} ...encoding
* @return {Boolean}
* @api public
*/
req.acceptsEncoding = function(encoding){
return !! ~this.acceptedEncodings.indexOf(encoding);
req.acceptsEncodings = function(){
var accept = accepts(this);
return accept.encodings.apply(accept, arguments);
};
req.acceptsEncoding = deprecate.function(req.acceptsEncodings,
'req.acceptsEncoding: Use acceptsEncodings instead');
/**
* Check if the given `charset` is acceptable,
* Check if the given `charset`s are acceptable,
* otherwise you should respond with 406 "Not Acceptable".
*
* @param {String} charset
* @param {String} ...charset
* @return {Boolean}
* @api public
*/
req.acceptsCharset = function(charset){
var accepted = this.acceptedCharsets;
return accepted.length
? !! ~accepted.indexOf(charset)
: true;
req.acceptsCharsets = function(){
var accept = accepts(this);
return accept.charsets.apply(accept, arguments);
};
req.acceptsCharset = deprecate.function(req.acceptsCharsets,
'req.acceptsCharset: Use acceptsCharsets instead');
/**
* Check if the given `lang` is acceptable,
* Check if the given `lang`s are acceptable,
* otherwise you should respond with 406 "Not Acceptable".
*
* @param {String} lang
* @param {String} ...lang
* @return {Boolean}
* @api public
*/
req.acceptsLanguage = function(lang){
var accepted = this.acceptedLanguages;
return accepted.length
? !! ~accepted.indexOf(lang)
: true;
req.acceptsLanguages = function(){
var accept = accepts(this);
return accept.languages.apply(accept, arguments);
};
req.acceptsLanguage = deprecate.function(req.acceptsLanguages,
'req.acceptsLanguage: Use acceptsLanguages instead');
/**
* Parse Range header field,
* capping to the given `size`.
@@ -174,98 +183,6 @@ req.range = function(size){
return parseRange(size, range);
};
/**
* Return an array of encodings.
*
* Examples:
*
* ['gzip', 'deflate']
*
* @return {Array}
* @api public
*/
req.__defineGetter__('acceptedEncodings', function(){
var accept = this.get('Accept-Encoding');
return accept
? accept.trim().split(/ *, */)
: [];
});
/**
* Return an array of Accepted media types
* ordered from highest quality to lowest.
*
* Examples:
*
* [ { value: 'application/json',
* quality: 1,
* type: 'application',
* subtype: 'json' },
* { value: 'text/html',
* quality: 0.5,
* type: 'text',
* subtype: 'html' } ]
*
* @return {Array}
* @api public
*/
req.__defineGetter__('accepted', function(){
var accept = this.get('Accept');
return accept
? utils.parseAccept(accept)
: [];
});
/**
* Return an array of Accepted languages
* ordered from highest quality to lowest.
*
* Examples:
*
* Accept-Language: en;q=.5, en-us
* ['en-us', 'en']
*
* @return {Array}
* @api public
*/
req.__defineGetter__('acceptedLanguages', function(){
var accept = this.get('Accept-Language');
return accept
? utils
.parseParams(accept)
.map(function(obj){
return obj.value;
})
: [];
});
/**
* Return an array of Accepted charsets
* ordered from highest quality to lowest.
*
* Examples:
*
* Accept-Charset: iso-8859-5;q=.2, unicode-1-1;q=0.8
* ['unicode-1-1', 'iso-8859-5']
*
* @return {Array}
* @api public
*/
req.__defineGetter__('acceptedCharsets', function(){
var accept = this.get('Accept-Charset');
return accept
? utils
.parseParams(accept)
.map(function(obj){
return obj.value;
})
: [];
});
/**
* Return the value of param `name` when present or `defaultValue`.
*
@@ -275,7 +192,7 @@ req.__defineGetter__('acceptedCharsets', function(){
*
* To utilize request bodies, `req.body`
* should be an object. This can be done by using
* the `connect.bodyParser()` middleware.
* the `bodyParser()` middleware.
*
* @param {String} name
* @param {Mixed} [defaultValue]
@@ -319,38 +236,38 @@ req.param = function(name, defaultValue){
* @api public
*/
req.is = function(type){
var ct = this.get('Content-Type');
if (!ct) return false;
ct = ct.split(';')[0];
if (!~type.indexOf('/')) type = mime.lookup(type);
if (~type.indexOf('*')) {
type = type.split('/');
ct = ct.split('/');
if ('*' == type[0] && type[1] == ct[1]) return true;
if ('*' == type[1] && type[0] == ct[0]) return true;
return false;
}
return !! ~ct.indexOf(type);
req.is = function(types){
if (!Array.isArray(types)) types = [].slice.call(arguments);
return typeis(this, types);
};
/**
* 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');
if (this.connection.encrypted) return 'https';
if (!trustProxy) return 'http';
var proto = this.get('X-Forwarded-Proto') || 'http';
defineGetter(req, 'protocol', function protocol(){
var proto = this.connection.encrypted
? 'https'
: '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];
});
@@ -363,71 +280,41 @@ req.__defineGetter__('protocol', function(){
* @api public
*/
req.__defineGetter__('secure', function(){
defineGetter(req, 'secure', function secure(){
return 'https' == this.protocol;
});
/**
* 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;
defineGetter(req, 'ip', function ip(){
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(/ *, */)
: [];
});
/**
* Return basic auth credentials.
*
* Examples:
*
* // http://tobi:hello@example.com
* req.auth
* // => { username: 'tobi', password: 'hello' }
*
* @return {Object} or undefined
* @api public
*/
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];
// credentials
auth = new Buffer(auth, 'base64').toString().match(/^([^:]*):(.*)$/);
if (!auth) return;
return { username: auth[1], password: auth[2] };
defineGetter(req, 'ips', function ips() {
var trust = this.app.get('trust proxy fn');
var addrs = proxyaddr.all(this, trust);
return addrs.slice(1).reverse();
});
/**
@@ -445,12 +332,17 @@ req.__defineGetter__('auth', function(){
* @api public
*/
req.__defineGetter__('subdomains', function(){
defineGetter(req, 'subdomains', function subdomains() {
var hostname = this.hostname;
if (!hostname) return [];
var offset = this.app.get('subdomain offset');
return (this.host || '')
.split('.')
.reverse()
.slice(offset);
var subdomains = !isIP(hostname)
? hostname.split('.').reverse()
: [hostname];
return subdomains.slice(offset);
});
/**
@@ -460,31 +352,48 @@ req.__defineGetter__('subdomains', function(){
* @api public
*/
req.__defineGetter__('path', function(){
defineGetter(req, 'path', function path() {
return parse(this).pathname;
});
/**
* Parse the "Host" header field hostname.
* Parse the "Host" header field to a hostname.
*
* When the "trust proxy" setting trusts the socket
* address, the "X-Forwarded-Host" header field will
* be trusted.
*
* @return {String}
* @api public
*/
req.__defineGetter__('host', function(){
var trustProxy = this.app.get('trust proxy');
var host = trustProxy && this.get('X-Forwarded-Host');
host = host || this.get('Host');
defineGetter(req, 'hostname', function hostname(){
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;
// IPv6 literal support
var offset = host[0] === '['
? host.indexOf(']') + 1
: 0;
var index = host.indexOf(':', offset);
return ~index
? host.substring(0, index)
: host;
});
// TODO: change req.host to return host in next major
defineGetter(req, 'host', deprecate.function(function host(){
return this.hostname;
}, 'req.host: Use req.hostname instead'));
/**
* Check if the request is fresh, aka
* Last-Modified and/or the ETag
@@ -494,7 +403,7 @@ req.__defineGetter__('host', function(){
* @api public
*/
req.__defineGetter__('fresh', function(){
defineGetter(req, 'fresh', function(){
var method = this.method;
var s = this.res.statusCode;
@@ -503,7 +412,7 @@ req.__defineGetter__('fresh', function(){
// 2xx or 304 as per rfc2616 14.26
if ((s >= 200 && s < 300) || 304 == s) {
return fresh(this.headers, this.res._headers);
return fresh(this.headers, (this.res._headers || {}));
}
return false;
@@ -518,7 +427,7 @@ req.__defineGetter__('fresh', function(){
* @api public
*/
req.__defineGetter__('stale', function(){
defineGetter(req, 'stale', function stale(){
return !this.fresh;
});
@@ -529,7 +438,23 @@ req.__defineGetter__('stale', function(){
* @api public
*/
req.__defineGetter__('xhr', function(){
defineGetter(req, 'xhr', function xhr(){
var val = this.get('X-Requested-With') || '';
return 'xmlhttprequest' == val.toLowerCase();
});
/**
* Helper function for creating a getter on an object.
*
* @param {Object} obj
* @param {String} name
* @param {Function} getter
* @api private
*/
function defineGetter(obj, name, getter) {
Object.defineProperty(obj, name, {
configurable: true,
enumerable: true,
get: getter
});
};

View File

@@ -2,21 +2,25 @@
* Module dependencies.
*/
var http = require('http')
, path = require('path')
, connect = require('connect')
, utils = connect.utils
, sign = require('cookie-signature').sign
, normalizeType = require('./utils').normalizeType
, normalizeTypes = require('./utils').normalizeTypes
, etag = require('./utils').etag
, statusCodes = http.STATUS_CODES
, cookie = require('cookie')
, send = require('send')
, mime = connect.mime
, resolve = require('url').resolve
, basename = path.basename
, extname = path.extname;
var contentDisposition = require('content-disposition');
var deprecate = require('depd')('express');
var escapeHtml = require('escape-html');
var http = require('http');
var isAbsolute = require('./utils').isAbsolute;
var onFinished = require('on-finished');
var path = require('path');
var merge = require('utils-merge');
var sign = require('cookie-signature').sign;
var normalizeType = require('./utils').normalizeType;
var normalizeTypes = require('./utils').normalizeTypes;
var setCharset = require('./utils').setCharset;
var statusCodes = http.STATUS_CODES;
var cookie = require('cookie');
var send = require('send');
var extname = path.extname;
var mime = send.mime;
var resolve = path.resolve;
var vary = require('vary');
/**
* Response prototype.
@@ -70,72 +74,100 @@ res.links = function(links){
* res.send(new Buffer('wahoo'));
* res.send({ some: 'json' });
* res.send('<p>some html</p>');
* res.send(404, 'Sorry, cant find that');
* res.send(404);
*
* @param {Mixed} body or status
* @param {Mixed} body
* @return {ServerResponse}
* @param {string|number|boolean|object|Buffer} body
* @api public
*/
res.send = function(body){
var req = this.req;
var head = 'HEAD' == req.method;
res.send = function send(body) {
var chunk = body;
var encoding;
var len;
var req = this.req;
var type;
// settings
var app = this.app;
// allow status / body
if (2 == arguments.length) {
if (arguments.length === 2) {
// res.send(body, status) backwards compat
if ('number' != typeof body && 'number' == typeof arguments[1]) {
if (typeof arguments[0] !== 'number' && typeof arguments[1] === 'number') {
deprecate('res.send(body, status): Use res.status(status).send(body) instead');
this.statusCode = arguments[1];
} else {
this.statusCode = body;
body = arguments[1];
deprecate('res.send(status, body): Use res.status(status).send(body) instead');
this.statusCode = arguments[0];
chunk = arguments[1];
}
}
switch (typeof body) {
// response status
case 'number':
this.get('Content-Type') || this.type('txt');
this.statusCode = body;
body = http.STATUS_CODES[body];
break;
// disambiguate res.send(status) and res.send(status, num)
if (typeof chunk === 'number' && arguments.length === 1) {
// res.send(status) will set status message as text string
if (!this.get('Content-Type')) {
this.type('txt');
}
deprecate('res.send(status): Use res.sendStatus(status) instead');
this.statusCode = chunk;
chunk = http.STATUS_CODES[chunk];
}
switch (typeof chunk) {
// string defaulting to html
case 'string':
if (!this.get('Content-Type')) {
this.charset = this.charset || 'utf-8';
this.type('html');
}
break;
case 'boolean':
case 'number':
case 'object':
if (null == body) {
body = '';
} else if (Buffer.isBuffer(body)) {
this.get('Content-Type') || this.type('bin');
if (chunk === null) {
chunk = '';
} else if (Buffer.isBuffer(chunk)) {
if (!this.get('Content-Type')) {
this.type('bin');
}
} else {
return this.json(body);
return this.json(chunk);
}
break;
}
// populate Content-Length
if (undefined !== body && !this.get('Content-Length')) {
this.set('Content-Length', len = Buffer.isBuffer(body)
? body.length
: Buffer.byteLength(body));
// write strings in utf-8
if (typeof chunk === 'string') {
encoding = 'utf8';
type = this.get('Content-Type');
// reflect this in content-type
if (typeof type === 'string') {
this.set('Content-Type', setCharset(type, 'utf-8'));
}
}
// populate Content-Length
if (chunk !== undefined) {
if (!Buffer.isBuffer(chunk)) {
// convert chunk to Buffer; saves later double conversions
chunk = new Buffer(chunk, encoding);
encoding = undefined;
}
len = chunk.length;
this.set('Content-Length', len);
}
// method check
var isHead = req.method === 'HEAD';
// ETag support
// TODO: W/ support
if (app.settings.etag && len && 'GET' == req.method) {
if (!this.get('ETag')) {
this.set('ETag', etag(body));
if (len !== undefined && (isHead || req.method === 'GET')) {
var etag = app.get('etag fn');
if (etag && !this.get('ETag')) {
etag = etag(chunk, encoding);
etag && this.set('ETag', etag);
}
}
@@ -147,11 +179,17 @@ res.send = function(body){
this.removeHeader('Content-Type');
this.removeHeader('Content-Length');
this.removeHeader('Transfer-Encoding');
body = '';
chunk = '';
}
if (isHead) {
// skip body for HEAD
this.end();
} else {
// respond
this.end(chunk, encoding);
}
// respond
this.end(head ? null : body);
return this;
};
@@ -162,24 +200,24 @@ res.send = function(body){
*
* res.json(null);
* res.json({ user: 'tj' });
* res.json(500, 'oh noes!');
* res.json(404, 'I dont have that');
*
* @param {Mixed} obj or status
* @param {Mixed} obj
* @return {ServerResponse}
* @param {string|number|boolean|object} obj
* @api public
*/
res.json = function(obj){
res.json = function json(obj) {
var val = obj;
// allow status / body
if (2 == arguments.length) {
if (arguments.length === 2) {
// res.json(body, status) backwards compat
if ('number' == typeof arguments[1]) {
if (typeof arguments[1] === 'number') {
deprecate('res.json(obj, status): Use res.status(status).json(obj) instead');
this.statusCode = arguments[1];
} else {
this.statusCode = obj;
obj = arguments[1];
deprecate('res.json(status, obj): Use res.status(status).json(obj) instead');
this.statusCode = arguments[0];
val = arguments[1];
}
}
@@ -187,11 +225,12 @@ res.json = 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);
var body = JSON.stringify(val, replacer, spaces);
// content-type
this.charset = this.charset || 'utf-8';
this.get('Content-Type') || this.set('Content-Type', 'application/json');
if (!this.get('Content-Type')) {
this.set('Content-Type', 'application/json');
}
return this.send(body);
};
@@ -203,24 +242,24 @@ res.json = function(obj){
*
* res.jsonp(null);
* res.jsonp({ user: 'tj' });
* res.jsonp(500, 'oh noes!');
* res.jsonp(404, 'I dont have that');
*
* @param {Mixed} obj or status
* @param {Mixed} obj
* @return {ServerResponse}
* @param {string|number|boolean|object} obj
* @api public
*/
res.jsonp = function(obj){
res.jsonp = function jsonp(obj) {
var val = obj;
// allow status / body
if (2 == arguments.length) {
if (arguments.length === 2) {
// res.json(body, status) backwards compat
if ('number' == typeof arguments[1]) {
if (typeof arguments[1] === 'number') {
deprecate('res.jsonp(obj, status): Use res.status(status).json(obj) instead');
this.statusCode = arguments[1];
} else {
this.statusCode = obj;
obj = arguments[1];
deprecate('res.jsonp(status, obj): Use res.status(status).jsonp(obj) instead');
this.statusCode = arguments[0];
val = arguments[1];
}
}
@@ -228,14 +267,14 @@ 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(val, 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.set('X-Content-Type-Options', 'nosniff');
this.set('Content-Type', 'application/json');
}
// fixup callback
if (Array.isArray(callback)) {
@@ -243,15 +282,51 @@ res.jsonp = function(obj){
}
// jsonp
if (callback && 'string' === typeof callback) {
if (typeof callback === 'string' && callback.length !== 0) {
this.charset = 'utf-8';
this.set('X-Content-Type-Options', 'nosniff');
this.set('Content-Type', 'text/javascript');
var cb = callback.replace(/[^\[\]\w$.]/g, '');
body = 'typeof ' + cb + ' === \'function\' && ' + cb + '(' + body + ');';
// restrict callback charset
callback = callback.replace(/[^\[\]\w$.]/g, '');
// replace chars not allowed in JavaScript that are in JSON
body = body
.replace(/\u2028/g, '\\u2028')
.replace(/\u2029/g, '\\u2029');
// the /**/ is a specific security mitigation for "Rosetta Flash JSONP abuse"
// the typeof check is just to reduce client error noise
body = '/**/ typeof ' + callback + ' === \'function\' && ' + callback + '(' + body + ');';
}
return this.send(body);
};
/**
* Send given HTTP status code.
*
* Sets the response status to `statusCode` and the body of the
* response to the standard description from node's http.STATUS_CODES
* or the statusCode number if no description.
*
* Examples:
*
* res.sendStatus(200);
*
* @param {number} statusCode
* @api public
*/
res.sendStatus = function sendStatus(statusCode) {
var body = http.STATUS_CODES[statusCode] || String(statusCode);
this.statusCode = statusCode;
this.type('txt');
return this.send(body);
};
/**
* Transfer the file at the given `path`.
*
@@ -263,8 +338,90 @@ res.jsonp = function(obj){
*
* Options:
*
* - `maxAge` defaulting to 0
* - `root` root directory for relative filenames
* - `maxAge` defaulting to 0 (can be string converted by `ms`)
* - `root` root directory for relative filenames
* - `headers` object of headers to serve with file
* - `dotfiles` serve dotfiles, defaulting to false; can be `"allow"` to send them
*
* Other options are passed along to `send`.
*
* Examples:
*
* The following example illustrates how `res.sendFile()` may
* be used as an alternative for the `static()` middleware for
* dynamic situations. The code backing `res.sendFile()` is actually
* the same code, so HTTP cache support etc is identical.
*
* app.get('/user/:uid/photos/:file', function(req, res){
* var uid = req.params.uid
* , file = req.params.file;
*
* req.user.mayViewFilesFrom(uid, function(yes){
* if (yes) {
* res.sendFile('/uploads/' + uid + '/' + file);
* } else {
* res.send(403, 'Sorry! you cant see that.');
* }
* });
* });
*
* @api public
*/
res.sendFile = function sendFile(path, options, fn) {
var req = this.req;
var res = this;
var next = req.next;
if (!path) {
throw new TypeError('path argument is required to res.sendFile');
}
// support function as second arg
if (typeof options === 'function') {
fn = options;
options = {};
}
options = options || {};
if (!options.root && !isAbsolute(path)) {
throw new TypeError('path must be absolute or specify root to res.sendFile');
}
// create file stream
var pathname = encodeURI(path);
var file = send(req, pathname, options);
// transfer
sendfile(res, file, options, function (err) {
if (fn) return fn(err);
if (err && err.code === 'EISDIR') return next();
// next() all but write errors
if (err && err.code !== 'ECONNABORT' && err.syscall !== 'write') {
next(err);
}
});
};
/**
* Transfer the file at the given `path`.
*
* Automatically sets the _Content-Type_ response header field.
* The callback `fn(err)` is invoked when the transfer is complete
* or when an error occurs. Be sure to check `res.sentHeader`
* if you wish to attempt responding, as the header and some data
* may have already been transferred.
*
* Options:
*
* - `maxAge` defaulting to 0 (can be string converted by `ms`)
* - `root` root directory for relative filenames
* - `headers` object of headers to serve with file
* - `dotfiles` serve dotfiles, defaulting to false; can be `"allow"` to send them
*
* Other options are passed along to `send`.
*
* Examples:
*
@@ -286,96 +443,71 @@ res.jsonp = function(obj){
* });
* });
*
* @param {String} path
* @param {Object|Function} options or fn
* @param {Function} fn
* @api public
*/
res.sendfile = function(path, options, fn){
var self = this
, req = self.req
, next = this.req.next
, options = options || {}
, done;
var req = this.req;
var res = this;
var next = req.next;
// support function as second arg
if ('function' == typeof options) {
if (typeof options === 'function') {
fn = options;
options = {};
}
// socket errors
req.socket.on('error', error);
options = options || {};
// errors
function error(err) {
if (done) return;
done = true;
// clean up
cleanup();
if (!self.headerSent) self.removeHeader('Content-Disposition');
// callback available
if (fn) return fn(err);
// list in limbo if there's no callback
if (self.headerSent) return;
// delegate
next(err);
}
// streaming
function stream(stream) {
if (done) return;
cleanup();
if (fn) stream.on('end', fn);
}
// cleanup
function cleanup() {
req.socket.removeListener('error', error);
}
// create file stream
var file = send(req, path, options);
// transfer
var file = send(req, path);
if (options.root) file.root(options.root);
file.maxage(options.maxAge || 0);
file.on('error', error);
file.on('directory', next);
file.on('stream', stream);
file.pipe(this);
this.on('finish', cleanup);
sendfile(res, file, options, function (err) {
if (fn) return fn(err);
if (err && err.code === 'EISDIR') return next();
// next() all but write errors
if (err && err.code !== 'ECONNABORT' && err.syscall !== 'write') {
next(err);
}
});
};
res.sendfile = deprecate.function(res.sendfile,
'res.sendfile: Use res.sendFile instead');
/**
* Transfer the file at the given `path` as an attachment.
*
* 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()`.
*
* @param {String} path
* @param {String|Function} filename or fn
* @param {Function} fn
* @api public
*/
res.download = function(path, filename, fn){
res.download = function download(path, filename, fn) {
// support function as second arg
if ('function' == typeof filename) {
if (typeof filename === 'function') {
fn = filename;
filename = null;
}
filename = filename || path;
this.set('Content-Disposition', 'attachment; filename="' + basename(filename) + '"');
return this.sendfile(path, fn);
// set Content-Disposition when file is sent
var headers = {
'Content-Disposition': contentDisposition(filename)
};
// Resolve the full path for sendFile
var fullPath = resolve(path);
return this.sendFile(fullPath, { headers: headers }, fn);
};
/**
@@ -460,8 +592,8 @@ res.type = function(type){
*/
res.format = function(obj){
var req = this.req
, next = req.next;
var req = this.req;
var next = req.next;
var fn = obj.default;
if (fn) delete obj.default;
@@ -472,10 +604,7 @@ res.format = function(obj){
this.vary("Accept");
if (key) {
var type = normalizeType(key).value;
var charset = mime.charsets.lookup(type);
if (charset) type += '; charset=' + charset;
this.set('Content-Type', type);
this.set('Content-Type', normalizeType(key).value);
obj[key](req, this, next);
} else if (fn) {
fn();
@@ -497,11 +626,13 @@ res.format = function(obj){
* @api public
*/
res.attachment = function(filename){
if (filename) this.type(extname(filename));
this.set('Content-Disposition', filename
? 'attachment; filename="' + basename(filename) + '"'
: 'attachment');
res.attachment = function attachment(filename) {
if (filename) {
this.type(extname(filename));
}
this.set('Content-Disposition', contentDisposition(filename));
return this;
};
@@ -524,10 +655,14 @@ res.attachment = function(filename){
*/
res.set =
res.header = function(field, val){
if (2 == arguments.length) {
res.header = function header(field, val) {
if (arguments.length === 2) {
if (Array.isArray(val)) val = val.map(String);
else val = String(val);
if ('content-type' == field.toLowerCase() && !/;\s*charset\s*=/.test(val)) {
var charset = mime.charsets.lookup(val.split(';')[0]);
if (charset) val += '; charset=' + charset.toLowerCase();
}
this.setHeader(field, val);
} else {
for (var key in field) {
@@ -554,14 +689,14 @@ res.get = function(field){
*
* @param {String} name
* @param {Object} options
* @param {ServerResponse} for chaining
* @return {ServerResponse} for chaining
* @api public
*/
res.clearCookie = function(name, options){
var opts = { expires: new Date(1), path: '/' };
return this.cookie(name, '', options
? utils.merge(opts, options)
? merge(opts, options)
: opts);
};
@@ -585,14 +720,15 @@ res.clearCookie = function(name, options){
* @param {String} name
* @param {String|Object} val
* @param {Options} options
* @return {ServerResponse} for chaining
* @api public
*/
res.cookie = function(name, val, options){
options = utils.merge({}, options);
options = merge({}, options);
var secret = this.req.secret;
var signed = options.signed;
if (signed && !secret) throw new Error('connect.cookieParser("secret") required for signed cookies');
if (signed && !secret) throw new Error('cookieParser("secret") required for signed cookies');
if ('number' == typeof val) val = val.toString();
if ('object' == typeof val) val = 'j:' + JSON.stringify(val);
if (signed) val = 's:' + sign(val, secret);
@@ -601,7 +737,18 @@ res.cookie = function(name, val, options){
options.maxAge /= 1000;
}
if (null == options.path) options.path = '/';
this.set('Set-Cookie', cookie.serialize(name, String(val), options));
var headerVal = cookie.serialize(name, String(val), options);
// supports multiple 'res.cookie' calls by getting previous value
var prev = this.get('Set-Cookie');
if (prev) {
if (Array.isArray(prev)) {
headerVal = prev.concat(headerVal);
} else {
headerVal = [prev, headerVal];
}
}
this.set('Set-Cookie', headerVal);
return this;
};
@@ -616,47 +763,19 @@ res.cookie = function(name, val, options){
*
* res.location('/foo/bar').;
* res.location('http://example.com');
* res.location('../login'); // /blog/post/1 -> /blog/login
*
* Mounting:
*
* When an application is mounted and `res.location()`
* is given a path that does _not_ lead with "/" it becomes
* relative to the mount-point. For example if the application
* is mounted at "/blog", the following would become "/blog/login".
*
* res.location('login');
*
* While the leading slash would result in a location of "/login":
*
* res.location('/login');
* res.location('../login');
*
* @param {String} url
* @return {ServerResponse} for chaining
* @api public
*/
res.location = function(url){
var app = this.app
, req = this.req
, path;
var req = this.req;
// "back" is an alias for the referrer
if ('back' == url) url = req.get('Referrer') || '/';
// relative
if (!~url.indexOf('://') && 0 != url.indexOf('//')) {
// relative to path
if ('.' == url[0]) {
path = req.originalUrl.split('?')[0];
path = path + ('/' == path[path.length - 1] ? '' : '/');
url = resolve(path, url);
// relative to mount-point
} else if ('/' != url[0]) {
path = app.path();
url = path + '/' + url;
}
}
// Respond
this.set('Location', url);
return this;
@@ -675,41 +794,39 @@ 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 head = 'HEAD' == this.req.method
, status = 302
, body;
res.redirect = function redirect(url) {
var address = url;
var body;
var status = 302;
// allow status / url
if (2 == arguments.length) {
if ('number' == typeof url) {
status = url;
url = arguments[1];
if (arguments.length === 2) {
if (typeof arguments[0] === 'number') {
status = arguments[0];
address = arguments[1];
} else {
deprecate('res.redirect(url, status): Use res.redirect(status, url) instead');
status = arguments[1];
}
}
// Set location header
this.location(url);
url = this.get('Location');
this.location(address);
address = this.get('Location');
// Support text/{plain,html} by default
this.format({
text: function(){
body = statusCodes[status] + '. Redirecting to ' + encodeURI(url);
body = statusCodes[status] + '. Redirecting to ' + encodeURI(address);
},
html: function(){
var u = utils.escape(url);
var u = escapeHtml(address);
body = '<p>' + statusCodes[status] + '. Redirecting to <a href="' + u + '">' + u + '</a></p>';
},
@@ -721,7 +838,12 @@ res.redirect = function(url){
// Respond
this.statusCode = status;
this.set('Content-Length', Buffer.byteLength(body));
this.end(head ? null : body);
if (this.req.method === 'HEAD') {
this.end();
}
this.end(body);
};
/**
@@ -729,36 +851,19 @@ res.redirect = function(url){
* this call is simply ignored.
*
* @param {Array|String} field
* @param {ServerResponse} for chaining
* @return {ServerResponse} for chaining
* @api public
*/
res.vary = function(field){
var self = this;
// nothing
if (!field) return this;
// array
if (Array.isArray(field)) {
field.forEach(function(field){
self.vary(field);
});
return;
}
var vary = this.get('Vary');
// append
if (vary) {
vary = vary.split(/ *, */);
if (!~vary.indexOf(field)) vary.push(field);
this.set('Vary', vary.join(', '));
// checks for back-compat
if (!field || (Array.isArray(field) && !field.length)) {
deprecate('res.vary(): Provide a field name');
return this;
}
// set
this.set('Vary', field);
vary(this, field);
return this;
};
@@ -772,17 +877,14 @@ res.vary = function(field){
* - `cache` boolean hinting to the engine it should cache
* - `filename` filename of the view being rendered
*
* @param {String} view
* @param {Object|Function} options or callback function
* @param {Function} fn
* @api public
*/
res.render = function(view, options, fn){
var self = this
, options = options || {}
, req = this.req
, app = req.app;
options = options || {};
var self = this;
var req = this.req;
var app = req.app;
// support callback function as second arg
if ('function' == typeof options) {
@@ -801,3 +903,69 @@ res.render = function(view, options, fn){
// render
app.render(view, options, fn);
};
// pipe the send file stream
function sendfile(res, file, options, callback) {
var done = false;
// directory
function ondirectory() {
if (done) return;
done = true;
var err = new Error('EISDIR, read');
err.code = 'EISDIR';
callback(err);
}
// errors
function onerror(err) {
if (done) return;
done = true;
callback(err);
}
// ended
function onend() {
if (done) return;
done = true;
callback();
}
// finished
function onfinish(err) {
if (err) return onerror(err);
if (done) return;
setImmediate(function () {
if (done) return;
done = true;
// response finished before end of file
var err = new Error('Request aborted');
err.code = 'ECONNABORT';
callback(err);
});
}
file.on('end', onend);
file.on('error', onerror);
file.on('directory', ondirectory);
onFinished(res, onfinish);
if (options.headers) {
// set headers on successful transfer
file.on('headers', function headers(res) {
var obj = options.headers;
var keys = Object.keys(obj);
for (var i = 0; i < keys.length; i++) {
var k = keys[i];
res.setHeader(k, obj[k]);
}
});
}
// pipe
file.pipe(res);
}

View File

@@ -1,49 +1,87 @@
/**
* 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 Layer = require('./layer');
var methods = require('methods');
var mixin = require('utils-merge');
var debug = require('debug')('express:router');
var parseUrl = require('parseurl');
var utils = require('../utils');
/**
* Expose `Router` constructor.
* Module variables.
*/
exports = module.exports = Router;
var objectRegExp = /^\[object (\S+)\]$/;
var slice = Array.prototype.slice;
var toString = Object.prototype.toString;
/**
* Initialize a new `Router` with the given `options`.
*
* @param {Object} options
* @api private
*/
function Router(options) {
options = options || {};
var self = this;
this.map = {};
this.params = {};
this._params = [];
this.caseSensitive = options.caseSensitive;
this.strict = options.strict;
this.middleware = function router(req, res, next){
self._dispatch(req, res, next);
};
}
/**
* Register a param callback `fn` for the given `name`.
*
* @param {String|Function} name
* @param {Function} fn
* @return {Router} for chaining
* @return {Router} which is an callable function
* @api public
*/
Router.prototype.param = function(name, fn){
var proto = module.exports = function(options) {
options = options || {};
function router(req, res, next) {
router.handle(req, res, next);
}
// mixin Router class functions
router.__proto__ = proto;
router.params = {};
router._params = [];
router.caseSensitive = options.caseSensitive;
router.mergeParams = options.mergeParams;
router.strict = options.strict;
router.stack = [];
return router;
};
/**
* Map the given param placeholder `name`(s) to the given callback.
*
* Parameter mapping is used to provide pre-conditions to routes
* which use normalized placeholders. For example a _:user_id_ parameter
* could automatically load a user's information from the database without
* any additional code,
*
* The callback uses the same signature as middleware, the only difference
* being that the value of the placeholder is passed, in this case the _id_
* of the user. Once the `next()` function is invoked, just like middleware
* it will continue on to execute the route, or subsequent parameter functions.
*
* Just like in middleware, you must either respond to the request or call next
* to avoid stalling the request.
*
* app.param('user_id', function(req, res, next, id){
* User.find(id, function(err, user){
* if (err) {
* return next(err);
* } else if (!user) {
* return next(new Error('failed to load user'));
* }
* req.user = user;
* next();
* });
* });
*
* @param {String} name
* @param {Function} fn
* @return {app} for chaining
* @api public
*/
proto.param = function(name, fn){
// param logic
if ('function' == typeof name) {
this._params.push(name);
@@ -51,9 +89,13 @@ Router.prototype.param = function(name, fn){
}
// apply param functions
var params = this._params
, len = params.length
, ret;
var params = this._params;
var len = params.length;
var ret;
if (name[0] === ':') {
name = name.substr(1);
}
for (var i = 0; i < len; ++i) {
if (ret = params[i](name, fn)) {
@@ -72,250 +114,463 @@ Router.prototype.param = function(name, fn){
};
/**
* Route dispatcher aka the route "middleware".
* Dispatch a req, res into the router.
*
* @param {IncomingMessage} req
* @param {ServerResponse} res
* @param {Function} next
* @api private
*/
Router.prototype._dispatch = function(req, res, next){
var params = this.params
, self = this;
proto.handle = function(req, res, done) {
var self = this;
debug('dispatching %s %s (%s)', req.method, req.url, req.originalUrl);
debug('dispatching %s %s', req.method, req.url);
// route dispatch
(function pass(i, err){
var paramCallbacks
, paramIndex = 0
, paramVal
, route
, keys
, key;
var search = 1 + req.url.indexOf('?');
var pathlength = search ? search - 1 : req.url.length;
var fqdn = req.url[0] !== '/' && 1 + req.url.substr(0, pathlength).indexOf('://');
var protohost = fqdn ? req.url.substr(0, req.url.indexOf('/', 2 + fqdn)) : '';
var idx = 0;
var removed = '';
var slashAdded = false;
var paramcalled = {};
// match next route
function nextRoute(err) {
pass(req._route_index + 1, err);
// store options for OPTIONS request
// only used if OPTIONS request
var options = [];
// middleware and routes
var stack = self.stack;
// manage inter-router variables
var parentParams = req.params;
var parentUrl = req.baseUrl || '';
done = restore(done, req, 'baseUrl', 'next', 'params');
// setup next layer
req.next = next;
// for options requests, respond with a default if nothing else responds
if (req.method === 'OPTIONS') {
done = wrap(done, function(old, err) {
if (err || options.length === 0) return old(err);
var body = options.join(',');
return res.set('Allow', body).send(body);
});
}
// setup basic req values
req.baseUrl = parentUrl;
req.originalUrl = req.originalUrl || req.url;
next();
function next(err) {
var layerError = err === 'route'
? null
: err;
var layer = stack[idx++];
if (slashAdded) {
req.url = req.url.substr(1);
slashAdded = false;
}
// match route
req.route = route = self.matchRequest(req, i);
if (removed.length !== 0) {
req.baseUrl = parentUrl;
req.url = protohost + removed + req.url.substr(protohost.length);
removed = '';
}
// implied OPTIONS
if (!route && 'OPTIONS' == req.method) return self._options(req, res, next);
if (!layer) {
setImmediate(done, layerError);
return;
}
// no route
if (!route) return next(err);
debug('matched %s %s', route.method, route.path);
// we have a route
// start at param 0
req.params = route.params;
keys = route.keys;
i = 0;
// param callbacks
function param(err) {
paramIndex = 0;
key = keys[i++];
paramVal = key && req.params[key.name];
paramCallbacks = key && params[key.name];
try {
if ('route' == err) {
nextRoute();
} else if (err) {
i = 0;
callbacks(err);
} else if (paramCallbacks && undefined !== paramVal) {
paramCallback();
} else if (key) {
param();
} else {
i = 0;
callbacks();
}
} catch (err) {
param(err);
self.match_layer(layer, req, res, function (err, path) {
if (err || path === undefined) {
return next(layerError || err);
}
// route object and not middleware
var route = layer.route;
// if final route, then we support options
if (route) {
// we don't run any routes with error first
if (layerError) {
return next(layerError);
}
var method = req.method;
var has_method = route._handles_method(method);
// build up automatic options response
if (!has_method && method === 'OPTIONS') {
options.push.apply(options, route._options());
}
// don't even bother
if (!has_method && method !== 'HEAD') {
return next();
}
// we can now dispatch to the route
req.route = route;
}
// Capture one-time layer values
req.params = self.mergeParams
? mergeParams(layer.params, parentParams)
: layer.params;
var layerPath = layer.path;
// this should be done for the layer
self.process_params(layer, paramcalled, req, res, function (err) {
if (err) {
return next(layerError || err);
}
if (route) {
return layer.handle_request(req, res, next);
}
trim_prefix(layer, layerError, layerPath, path);
});
});
}
function trim_prefix(layer, layerError, layerPath, path) {
var c = path[layerPath.length];
if (c && '/' !== c && '.' !== c) return next(layerError);
// Trim off the part of the url that matches the route
// middleware (.use stuff) needs to have the path stripped
if (layerPath.length !== 0) {
debug('trim prefix (%s) from url %s', layerPath, req.url);
removed = layerPath;
req.url = protohost + req.url.substr(protohost.length + removed.length);
// Ensure leading slash
if (!fqdn && req.url[0] !== '/') {
req.url = '/' + req.url;
slashAdded = true;
}
// Setup base URL (no trailing slash)
req.baseUrl = parentUrl + (removed[removed.length - 1] === '/'
? removed.substring(0, removed.length - 1)
: removed);
}
debug('%s %s : %s', layer.name, layerPath, req.originalUrl);
if (layerError) {
layer.handle_error(layerError, req, res, next);
} else {
layer.handle_request(req, res, next);
}
}
};
/**
* Match request to a layer.
*
* @api private
*/
proto.match_layer = function match_layer(layer, req, res, done) {
var error = null;
var path;
try {
path = parseUrl(req).pathname;
if (!layer.match(path)) {
path = undefined;
}
} catch (err) {
error = err;
}
done(error, path);
};
/**
* Process any parameters for the layer.
*
* @api private
*/
proto.process_params = function(layer, called, req, res, done) {
var params = this.params;
// captured parameters from the layer, keys and values
var keys = layer.keys;
// fast track
if (!keys || keys.length === 0) {
return done();
}
var i = 0;
var name;
var paramIndex = 0;
var key;
var paramVal;
var paramCallbacks;
var paramCalled;
// process params in order
// param callbacks can be async
function param(err) {
if (err) {
return done(err);
}
if (i >= keys.length ) {
return done();
}
paramIndex = 0;
key = keys[i++];
if (!key) {
return done();
}
name = key.name;
paramVal = req.params[name];
paramCallbacks = params[name];
paramCalled = called[name];
if (paramVal === undefined || !paramCallbacks) {
return param();
}
// param previously called with same value or error occurred
if (paramCalled && (paramCalled.error || paramCalled.match === paramVal)) {
// restore value
req.params[name] = paramCalled.value;
// next param
return param(paramCalled.error);
}
called[name] = paramCalled = {
error: null,
match: paramVal,
value: paramVal
};
param(err);
paramCallback();
}
// single param callbacks
function paramCallback(err) {
var fn = paramCallbacks[paramIndex++];
if (err || !fn) return param(err);
// single param callbacks
function paramCallback(err) {
var fn = paramCallbacks[paramIndex++];
// store updated value
paramCalled.value = req.params[key.name];
if (err) {
// store error
paramCalled.error = err;
param(err);
return;
}
if (!fn) return param();
try {
fn(req, res, paramCallback, paramVal, key.name);
}
// invoke route callbacks
function callbacks(err) {
var fn = route.callbacks[i++];
try {
if ('route' == err) {
nextRoute();
} else if (err && fn) {
if (fn.length < 4) return callbacks(err);
fn(err, req, res, callbacks);
} else if (fn) {
if (fn.length < 4) return fn(req, res, callbacks);
callbacks();
} else {
nextRoute(err);
}
} catch (err) {
callbacks(err);
}
}
})(0);
};
/**
* Respond to __OPTIONS__ method.
*
* @param {IncomingMessage} req
* @param {ServerResponse} res
* @api private
*/
Router.prototype._options = function(req, res, next){
var path = parse(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`
* defaulting to 0.
*
* @param {IncomingMessage} req
* @param {Number} i
* @return {Route}
* @api private
*/
Router.prototype.matchRequest = function(req, i, head){
var method = req.method.toLowerCase()
, url = parse(req)
, path = url.pathname
, routes = this.map
, i = i || 0
, route;
// HEAD support
if (!head && 'head' == method) {
route = this.matchRequest(req, i, true);
if (route) return route;
method = 'get';
}
// routes for this method
if (routes = routes[method]) {
// matching routes
for (var len = routes.length; i < len; ++i) {
route = routes[i];
if (route.match(path)) {
req._route_index = i;
return route;
}
} catch (e) {
paramCallback(e);
}
}
param();
};
/**
* Attempt to match a route for `method`
* and `url` with optional starting
* index of `i` defaulting to 0.
* Use the given middleware function, with optional path, defaulting to "/".
*
* @param {String} method
* @param {String} url
* @param {Number} i
* @return {Route}
* @api private
* Use (like `.all`) will run for any http METHOD, but it will not add
* handlers for those methods so OPTIONS requests will not consider `.use`
* functions even if they could respond.
*
* The other difference is that _route_ path is stripped and not visible
* to the handler function. The main effect of this feature is that mounted
* handlers can operate without any code changes regardless of the "prefix"
* pathname.
*
* @api public
*/
Router.prototype.match = function(method, url, i, head){
var req = { method: method, url: url };
return this.matchRequest(req, i, head);
proto.use = function use(fn) {
var offset = 0;
var path = '/';
// default path to '/'
// disambiguate router.use([fn])
if (typeof fn !== 'function') {
var arg = fn;
while (Array.isArray(arg) && arg.length !== 0) {
arg = arg[0];
}
// first arg is the path
if (typeof arg !== 'function') {
offset = 1;
path = fn;
}
}
var callbacks = utils.flatten(slice.call(arguments, offset));
if (callbacks.length === 0) {
throw new TypeError('Router.use() requires middleware functions');
}
callbacks.forEach(function (fn) {
if (typeof fn !== 'function') {
throw new TypeError('Router.use() requires middleware function but got a ' + gettype(fn));
}
// add the middleware
debug('use %s %s', path, fn.name || '<anonymous>');
var layer = new Layer(path, {
sensitive: this.caseSensitive,
strict: false,
end: false
}, fn);
layer.route = undefined;
this.stack.push(layer);
}, this);
return this;
};
/**
* Route `method`, `path`, and one or more callbacks.
* Create a new Route for the given path.
*
* Each route contains a separate middleware stack and VERB handlers.
*
* See the Route api documentation for details on adding handlers
* and middleware to routes.
*
* @param {String} method
* @param {String} path
* @param {Function} callback...
* @return {Router} for chaining
* @api private
* @return {Route}
* @api public
*/
Router.prototype.route = function(method, path, callbacks){
var method = method.toLowerCase()
, callbacks = utils.flatten([].slice.call(arguments, 2));
proto.route = function(path){
var route = new Route(path);
// ensure path was given
if (!path) throw new Error('Router#' + method + '() requires a path');
// ensure all callbacks are functions
callbacks.forEach(function(fn){
if ('function' == typeof fn) return;
var type = {}.toString.call(fn);
var msg = '.' + method + '() requires callback functions but got a ' + type;
throw new Error(msg);
});
// create the route
debug('defined %s %s', method, path);
var route = new Route(method, path, callbacks, {
var layer = new Layer(path, {
sensitive: this.caseSensitive,
strict: this.strict
});
strict: this.strict,
end: true
}, route.dispatch.bind(route));
// add it
(this.map[method] = this.map[method] || []).push(route);
return this;
layer.route = route;
this.stack.push(layer);
return route;
};
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));
this.route.apply(this, args);
// create Router#VERB functions
methods.concat('all').forEach(function(method){
proto[method] = function(path){
var route = this.route(path)
route[method].apply(route, slice.call(arguments, 1));
return this;
};
});
// get type for error message
function gettype(obj) {
var type = typeof obj;
if (type !== 'object') {
return type;
}
// inspect [[Class]] for objects
return toString.call(obj)
.replace(objectRegExp, '$1');
}
// merge params with parent params
function mergeParams(params, parent) {
if (typeof parent !== 'object' || !parent) {
return params;
}
// make copy of parent for base
var obj = mixin({}, parent);
// simple non-numeric merging
if (!(0 in params) || !(0 in parent)) {
return mixin(obj, params);
}
var i = 0;
var o = 0;
// determine numeric gaps
while (i === o || o in parent) {
if (i in params) i++;
if (o in parent) o++;
}
// offset numeric indices in params before merge
for (i--; i >= 0; i--) {
params[i + o] = params[i];
// create holes for the merge when necessary
if (i < o) {
delete params[i];
}
}
return mixin(parent, params);
}
// restore obj props after function
function restore(fn, obj) {
var props = new Array(arguments.length - 2);
var vals = new Array(arguments.length - 2);
for (var i = 0; i < props.length; i++) {
props[i] = arguments[i + 2];
vals[i] = obj[props[i]];
}
return function(err){
// restore vals
for (var i = 0; i < props.length; i++) {
obj[props[i]] = vals[i];
}
return fn.apply(this, arguments);
};
}
// wrap a function
function wrap(old, fn) {
return function proxy() {
var args = new Array(arguments.length + 1);
args[0] = old;
for (var i = 0, len = arguments.length; i < len; i++) {
args[i + 1] = arguments[i];
}
fn.apply(this, args);
};
}

166
lib/router/layer.js Normal file
View File

@@ -0,0 +1,166 @@
/**
* Module dependencies.
*/
var pathRegexp = require('path-to-regexp');
var debug = require('debug')('express:router:layer');
/**
* Module variables.
*/
var hasOwnProperty = Object.prototype.hasOwnProperty;
/**
* Expose `Layer`.
*/
module.exports = Layer;
function Layer(path, options, fn) {
if (!(this instanceof Layer)) {
return new Layer(path, options, fn);
}
debug('new %s', path);
options = options || {};
this.handle = fn;
this.name = fn.name || '<anonymous>';
this.params = undefined;
this.path = undefined;
this.regexp = pathRegexp(path, this.keys = [], options);
if (path === '/' && options.end === false) {
this.regexp.fast_slash = true;
}
}
/**
* Handle the error for the layer.
*
* @param {Error} error
* @param {Request} req
* @param {Response} res
* @param {function} next
* @api private
*/
Layer.prototype.handle_error = function handle_error(error, req, res, next) {
var fn = this.handle;
if (fn.length !== 4) {
// not a standard error handler
return next(error);
}
try {
fn(error, req, res, next);
} catch (err) {
next(err);
}
};
/**
* Handle the request for the layer.
*
* @param {Request} req
* @param {Response} res
* @param {function} next
* @api private
*/
Layer.prototype.handle_request = function handle(req, res, next) {
var fn = this.handle;
if (fn.length > 3) {
// not a standard request handler
return next();
}
try {
fn(req, res, next);
} catch (err) {
next(err);
}
};
/**
* Check if this route matches `path`, if so
* populate `.params`.
*
* @param {String} path
* @return {Boolean}
* @api private
*/
Layer.prototype.match = function match(path) {
if (path == null) {
// no path, nothing matches
this.params = undefined;
this.path = undefined;
return false;
}
if (this.regexp.fast_slash) {
// fast path non-ending match for / (everything matches)
this.params = {};
this.path = '';
return true;
}
var m = this.regexp.exec(path);
if (!m) {
this.params = undefined;
this.path = undefined;
return false;
}
// store values
this.params = {};
this.path = m[0];
var keys = this.keys;
var params = this.params;
var prop;
var n = 0;
var key;
var val;
for (var i = 1, len = m.length; i < len; ++i) {
key = keys[i - 1];
prop = key
? key.name
: n++;
val = decode_param(m[i]);
if (val !== undefined || !(hasOwnProperty.call(params, prop))) {
params[prop] = val;
}
}
return true;
};
/**
* Decode param value.
*
* @param {string} val
* @return {string}
* @api private
*/
function decode_param(val){
if (typeof val !== 'string') {
return val;
}
try {
return decodeURIComponent(val);
} catch (e) {
var err = new TypeError("Failed to decode param '" + val + "'");
err.status = 400;
throw err;
}
}

View File

@@ -1,8 +1,10 @@
/**
* Module dependencies.
*/
var debug = require('debug')('express:router:route');
var Layer = require('./layer');
var methods = require('methods');
var utils = require('../utils');
/**
@@ -12,67 +14,160 @@ var utils = require('../utils');
module.exports = Route;
/**
* Initialize `Route` with the given HTTP `method`, `path`,
* and an array of `callbacks` and `options`.
* Initialize `Route` with the given `path`,
*
* Options:
*
* - `sensitive` enable case-sensitive routes
* - `strict` enable strict matching for trailing slashes
*
* @param {String} method
* @param {String} path
* @param {Array} callbacks
* @param {Object} options.
* @api private
*/
function Route(method, path, callbacks, options) {
options = options || {};
function Route(path) {
debug('new %s', path);
this.path = path;
this.method = method;
this.callbacks = callbacks;
this.regexp = utils.pathRegexp(path
, this.keys = []
, options.sensitive
, options.strict);
this.stack = [];
// route handlers for various http methods
this.methods = {};
}
/**
* Check if this route matches `path`, if so
* populate `.params`.
*
* @param {String} path
* @return {Boolean}
* @api private
*/
Route.prototype.match = function(path){
var keys = this.keys
, params = this.params = []
, m = this.regexp.exec(path);
if (!m) return false;
for (var i = 1, len = m.length; i < len; ++i) {
var key = keys[i - 1];
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;
} else {
params.push(val);
}
Route.prototype._handles_method = function _handles_method(method) {
if (this.methods._all) {
return true;
}
return true;
method = method.toLowerCase();
if (method === 'head' && !this.methods['head']) {
method = 'get';
}
return Boolean(this.methods[method]);
};
/**
* @return {Array} supported HTTP methods
* @api private
*/
Route.prototype._options = function(){
return Object.keys(this.methods).map(function(method) {
return method.toUpperCase();
});
};
/**
* dispatch req, res into this route
*
* @api private
*/
Route.prototype.dispatch = function(req, res, done){
var idx = 0;
var stack = this.stack;
if (stack.length === 0) {
return done();
}
var method = req.method.toLowerCase();
if (method === 'head' && !this.methods['head']) {
method = 'get';
}
req.route = this;
next();
function next(err) {
if (err && err === 'route') {
return done();
}
var layer = stack[idx++];
if (!layer) {
return done(err);
}
if (layer.method && layer.method !== method) {
return next(err);
}
if (err) {
layer.handle_error(err, req, res, next);
} else {
layer.handle_request(req, res, next);
}
}
};
/**
* Add a handler for all HTTP verbs to this route.
*
* Behaves just like middleware and can respond or call `next`
* to continue processing.
*
* You can use multiple `.all` call to add multiple handlers.
*
* function check_something(req, res, next){
* next();
* };
*
* function validate_user(req, res, next){
* next();
* };
*
* route
* .all(validate_user)
* .all(check_something)
* .get(function(req, res, next){
* res.send('hello world');
* });
*
* @param {function} handler
* @return {Route} for chaining
* @api public
*/
Route.prototype.all = function(){
var callbacks = utils.flatten([].slice.call(arguments));
callbacks.forEach(function(fn) {
if (typeof fn !== 'function') {
var type = {}.toString.call(fn);
var msg = 'Route.all() requires callback functions but got a ' + type;
throw new Error(msg);
}
var layer = Layer('/', {}, fn);
layer.method = undefined;
this.methods._all = true;
this.stack.push(layer);
}, this);
return this;
};
methods.forEach(function(method){
Route.prototype[method] = function(){
var callbacks = utils.flatten([].slice.call(arguments));
callbacks.forEach(function(fn) {
if (typeof fn !== 'function') {
var type = {}.toString.call(fn);
var msg = 'Route.' + method + '() requires callback functions but got a ' + type;
throw new Error(msg);
}
debug('%s %s', method, this.path);
var layer = Layer('/', {}, fn);
layer.method = method;
this.methods[method] = true;
this.stack.push(layer);
}, this);
return this;
};
});

View File

@@ -1,46 +1,49 @@
/**
* Module dependencies.
*/
var mime = require('connect').mime
, crc32 = require('buffer-crc32');
var contentDisposition = require('content-disposition');
var deprecate = require('depd')('express');
var mime = require('send').mime;
var basename = require('path').basename;
var etag = require('etag');
var proxyaddr = require('proxy-addr');
var qs = require('qs');
var querystring = require('querystring');
var typer = require('media-typer');
/**
* toString ref.
*/
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 (body, encoding) {
var buf = !Buffer.isBuffer(body)
? new Buffer(body, encoding)
: body;
return etag(buf, {weak: false});
};
/**
* Make `locals()` bound to the given `obj`.
* Return weak ETag for `body`.
*
* This is used for `app.locals` and `res.locals`.
*
* @param {Object} obj
* @return {Function}
* @param {String|Buffer} body
* @param {String} [encoding]
* @return {String}
* @api private
*/
exports.locals = function(){
function locals(obj){
for (var key in obj) locals[key] = obj[key];
return obj;
};
exports.wetag = function wetag(body, encoding){
var buf = !Buffer.isBuffer(body)
? new Buffer(body, encoding)
: body;
return locals;
return etag(buf, {weak: true});
};
/**
@@ -66,8 +69,8 @@ exports.isAbsolute = function(path){
*/
exports.flatten = function(arr, ret){
var ret = ret || []
, len = arr.length;
ret = ret || [];
var len = arr.length;
for (var i = 0; i < len; ++i) {
if (Array.isArray(arr[i])) {
exports.flatten(arr[i], ret);
@@ -111,126 +114,16 @@ exports.normalizeTypes = function(types){
};
/**
* Return the acceptable type in `types`, if any.
* Generate Content-Disposition header appropriate for the filename.
* non-ascii filenames are urlencoded and a filename* parameter is added
*
* @param {Array} types
* @param {String} str
* @param {String} filename
* @return {String}
* @api private
*/
exports.acceptsArray = function(types, str){
// accept anything when Accept is not present
if (!str) return types[0];
// parse
var accepted = exports.parseAccept(str)
, normalized = exports.normalizeTypes(types)
, len = accepted.length;
for (var i = 0; i < len; ++i) {
for (var j = 0, jlen = types.length; j < jlen; ++j) {
if (exports.accept(normalized[j], accepted[i])) {
return types[j];
}
}
}
};
/**
* Check if `type(s)` are acceptable based on
* the given `str`.
*
* @param {String|Array} type(s)
* @param {String} str
* @return {Boolean|String}
* @api private
*/
exports.accepts = function(type, str){
if ('string' == typeof type) type = type.split(/ *, */);
return exports.acceptsArray(type, str);
};
/**
* Check if `type` array is acceptable for `other`.
*
* @param {Object} type
* @param {Object} other
* @return {Boolean}
* @api private
*/
exports.accept = function(type, other){
var t = type.value.split('/');
return (t[0] == other.type || '*' == other.type)
&& (t[1] == other.subtype || '*' == other.subtype)
&& paramsEqual(type.params, other.params);
};
/**
* Check if accept params are equal.
*
* @param {Object} a
* @param {Object} b
* @return {Boolean}
* @api private
*/
function paramsEqual(a, b){
return !Object.keys(a).some(function(k) {
return a[k] != b[k];
});
}
/**
* Parse accept `str`, returning
* an array objects containing
* `.type` and `.subtype` along
* with the values provided by
* `parseQuality()`.
*
* @param {Type} name
* @return {Type}
* @api private
*/
exports.parseAccept = function(str){
return exports
.parseParams(str)
.map(function(obj){
var parts = obj.value.split('/');
obj.type = parts[0];
obj.subtype = parts[1];
return obj;
});
};
/**
* Parse quality `str`, returning an
* array of objects with `.value`,
* `.quality` and optional `.params`
*
* @param {String} str
* @return {Array}
* @api private
*/
exports.parseParams = function(str){
return str
.split(/ *, */)
.map(acceptParams)
.filter(function(obj){
return obj.quality;
})
.sort(function(a, b){
if (a.quality === b.quality) {
return a.originalIndex - b.originalIndex;
} else {
return b.quality - a.quality;
}
});
};
exports.contentDisposition = deprecate.function(contentDisposition,
'utils.contentDisposition: use content-disposition npm module instead');
/**
* Parse accept params `str` returning an
@@ -259,56 +152,132 @@ function acceptParams(str, index) {
}
/**
* Escape special characters in the given string of html.
* Compile "etag" value to function.
*
* @param {String} html
* @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 "query parser" value to function.
*
* @param {String|Function} val
* @return {Function}
* @api private
*/
exports.compileQueryParser = function compileQueryParser(val) {
var fn;
if (typeof val === 'function') {
return val;
}
switch (val) {
case true:
fn = querystring.parse;
break;
case false:
fn = newObject;
break;
case 'extended':
fn = qs.parse;
break;
case 'simple':
fn = querystring.parse;
break;
default:
throw new TypeError('unknown value for query parser 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.escape = function(html) {
return String(html)
.replace(/&/g, '&amp;')
.replace(/"/g, '&quot;')
.replace(/</g, '&lt;')
.replace(/>/g, '&gt;');
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);
};
/**
* Normalize the given path string,
* returning a regular expression.
* Return new empty objet.
*
* An empty array should be passed,
* which will contain the placeholder
* key names. For example "/user/:id" will
* then contain ["id"].
*
* @param {String|RegExp|Array} path
* @param {Array} keys
* @param {Boolean} sensitive
* @param {Boolean} strict
* @return {RegExp}
* @return {Object}
* @api private
*/
exports.pathRegexp = function(path, keys, sensitive, strict) {
if (toString.call(path) == '[object RegExp]') return path;
if (Array.isArray(path)) path = '(' + path.join('|') + ')';
path = path
.concat(strict ? '' : '/?')
.replace(/\/\(/g, '(?:/')
.replace(/(\/)?(\.)?:(\w+)(?:(\(.*?\)))?(\?)?(\*)?/g, function(_, slash, format, key, capture, optional, star){
keys.push({ name: key, optional: !! optional });
slash = slash || '';
return ''
+ (optional ? '' : slash)
+ '(?:'
+ (optional ? slash : '')
+ (format || '') + (capture || (format && '([^/.]+?)' || '([^/]+?)')) + ')'
+ (optional || '')
+ (star ? '(/*)?' : '');
})
.replace(/([\/.])/g, '\\$1')
.replace(/\*/g, '(.*)');
return new RegExp('^' + path + '$', sensitive ? '' : 'i');
function newObject() {
return {};
}

View File

@@ -2,14 +2,21 @@
* Module dependencies.
*/
var path = require('path')
, fs = require('fs')
, utils = require('./utils')
, dirname = path.dirname
, basename = path.basename
, extname = path.extname
, exists = fs.existsSync || path.existsSync
, join = path.join;
var debug = require('debug')('express:view');
var path = require('path');
var fs = require('fs');
var utils = require('./utils');
/**
* Module variables.
* @private
*/
var dirname = path.dirname;
var basename = path.basename;
var extname = path.extname;
var join = path.join;
var resolve = path.resolve;
/**
* Expose `View`.
@@ -45,23 +52,32 @@ function View(name, options) {
}
/**
* Lookup view by the given `path`
* Lookup view by the given `name`
*
* @param {String} path
* @param {String} name
* @return {String}
* @api private
*/
View.prototype.lookup = function(path){
var ext = this.ext;
View.prototype.lookup = function lookup(name) {
var path;
var roots = [].concat(this.root);
// <path>.<engine>
if (!utils.isAbsolute(path)) path = join(this.root, path);
if (exists(path)) return path;
debug('lookup "%s"', name);
// <path>/index.<engine>
path = join(dirname(path), basename(path, ext), 'index' + ext);
if (exists(path)) return path;
for (var i = 0; i < roots.length && !path; i++) {
var root = roots[i];
// resolve the path
var loc = resolve(root, name);
var dir = dirname(loc);
var file = basename(loc);
// resolve the file
path = this.resolve(dir, file);
}
return path;
};
/**
@@ -72,6 +88,55 @@ View.prototype.lookup = function(path){
* @api private
*/
View.prototype.render = function(options, fn){
View.prototype.render = function render(options, fn) {
debug('render "%s"', this.path);
this.engine(this.path, options, fn);
};
/**
* Resolve the file within the given directory.
*
* @param {string} dir
* @param {string} file
* @private
*/
View.prototype.resolve = function resolve(dir, file) {
var ext = this.ext;
var path;
var stat;
// <path>.<ext>
path = join(dir, file);
stat = tryStat(path);
if (stat && stat.isFile()) {
return path;
}
// <path>/index.<ext>
path = join(dir, basename(file, ext), 'index' + ext);
stat = tryStat(path);
if (stat && stat.isFile()) {
return path;
}
};
/**
* Return a stat, maybe.
*
* @param {string} path
* @return {fs.Stats}
* @private
*/
function tryStat(path) {
debug('stat "%s"', path);
try {
return fs.statSync(path);
} catch (e) {
return undefined;
}
}

View File

@@ -1,51 +1,20 @@
{
"name": "express",
"description": "Sinatra inspired web development framework",
"version": "3.5.3",
"description": "Fast, unopinionated, minimalist web framework",
"version": "4.10.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>",
"Young Jae Sim <hanul@hanul.me>"
],
"dependencies": {
"connect": "2.14.5",
"commander": "1.3.2",
"range-parser": "1.0.0",
"mkdirp": "0.4.0",
"cookie": "0.1.2",
"buffer-crc32": "0.2.1",
"fresh": "0.2.2",
"methods": "0.1.0",
"send": "0.3.0",
"cookie-signature": "1.0.3",
"merge-descriptors": "0.0.2",
"debug": ">= 0.7.3 < 1"
},
"devDependencies": {
"ejs": "~0.8.4",
"mocha": "~1.18.2",
"jade": "~0.30.0",
"hjs": "~0.0.6",
"stylus": "~0.40.0",
"should": "~2.1.1",
"connect-redis": "~1.4.5",
"marked": "0.2.10",
"supertest": "~0.11.0"
},
"license": "MIT",
"repository": "strongloop/express",
"homepage": "http://expressjs.com/",
"keywords": [
"express",
"framework",
@@ -57,17 +26,65 @@
"app",
"api"
],
"repository": "git://github.com/visionmedia/express",
"main": "index",
"bin": {
"express": "./bin/express"
"dependencies": {
"accepts": "~1.1.4",
"content-disposition": "0.5.0",
"cookie-signature": "1.0.5",
"debug": "~2.1.0",
"depd": "~1.0.0",
"escape-html": "1.0.1",
"etag": "~1.5.1",
"finalhandler": "0.3.2",
"fresh": "0.2.4",
"media-typer": "0.3.0",
"methods": "1.1.0",
"on-finished": "~2.1.1",
"parseurl": "~1.3.0",
"path-to-regexp": "0.1.3",
"proxy-addr": "~1.0.4",
"qs": "2.3.3",
"range-parser": "~1.0.2",
"send": "0.10.1",
"serve-static": "~1.7.1",
"type-is": "~1.5.4",
"vary": "~1.0.0",
"cookie": "0.1.2",
"merge-descriptors": "0.0.2",
"utils-merge": "1.0.0"
},
"scripts": {
"prepublish": "npm prune",
"test": "make test"
"devDependencies": {
"after": "0.8.1",
"istanbul": "0.3.5",
"mocha": "~2.0.0",
"should": "~4.3.1",
"supertest": "~0.15.0",
"ejs": "~1.0.0",
"marked": "0.3.2",
"hjs": "~0.0.6",
"body-parser": "~1.9.3",
"connect-redis": "~2.1.0",
"cookie-parser": "~1.3.3",
"express-session": "~1.9.2",
"jade": "~1.7.0",
"method-override": "~2.3.0",
"morgan": "~1.5.0",
"multiparty": "~4.0.0",
"vhost": "~3.0.0"
},
"engines": {
"node": ">= 0.8.0"
"node": ">= 0.10.0"
},
"license": "MIT"
"files": [
"LICENSE",
"History.md",
"Readme.md",
"index.js",
"lib/"
],
"scripts": {
"test": "mocha --require test/support/env --reporter spec --bail --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/"
}
}

View File

@@ -1,66 +0,0 @@
/**
* Module dependencies.
*/
var express = require('../');
var app = express()
, blog = express()
, admin = express();
// app.use(express.logger('dev'))
blog.use('/admin', admin);
app.use('/blog', blog);
app.set('views', __dirname + '/views');
app.set('view engine', 'jade');
app.locals.self = true;
app.get('/render', function(req, res){
res.render('hello');
});
admin.get('/', function(req, res){
res.send('Hello World\n');
});
blog.get('/', function(req, res){
res.send('Hello World\n');
});
app.get('/', function(req, res){
res.send('Hello World\n');
});
app.get('/json', function(req, res){
res.send({ name: 'Tobi', role: 'admin' });
});
app.get('/json/:n', function(req, res){
var n = ~~req.params.n;
var arr = [];
var obj = { name: 'Tobi', role: 'admin' };
while (n--) arr.push(obj);
res.send(arr);
});
function foo(req, res, next) {
next();
}
app.get('/middleware', foo, foo, foo, foo, function(req, res){
res.send('Hello World\n');
});
var n = 100;
while (n--) {
app.get('/foo', foo, foo, function(req, res){
});
}
app.get('/match', function(req, res){
res.send('Hello World\n');
});
app.listen(8000);

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