Compare commits

...

666 Commits

Author SHA1 Message Date
Douglas Christopher Wilson
0437c513f2 4.14.1 2017-01-28 17:21:24 -05:00
Douglas Christopher Wilson
1f70b76c45 build: Node.js@4.7 2017-01-28 16:56:34 -05:00
Douglas Christopher Wilson
0b39fa2f7c build: should@11.2.0 2017-01-28 16:40:40 -05:00
Douglas Christopher Wilson
0d6c64fdfd deps: type-is@~1.6.14 2017-01-26 22:54:05 -05:00
Douglas Christopher Wilson
c238aca438 examples: remove big-view example 2017-01-26 22:48:08 -05:00
Douglas Christopher Wilson
6b506d801a examples: fix mvc example to ignore files in controllers dir
fixes #3182
2017-01-26 22:33:52 -05:00
Douglas Christopher Wilson
dc48f27f60 deps: update example dependencies 2017-01-26 22:25:39 -05:00
Douglas Christopher Wilson
8e14e06ebf deps: serve-static@~1.11.2 2017-01-24 07:40:20 -08:00
Douglas Christopher Wilson
572657ee4a deps: send@0.14.2 2017-01-23 10:43:11 -05:00
Douglas Christopher Wilson
cfae537d3b deps: finalhandler@0.5.1 2017-01-21 01:05:17 -05:00
Douglas Christopher Wilson
a3d635309c deps: proxy-addr@~1.1.3 2017-01-21 01:00:52 -05:00
Douglas Christopher Wilson
a2e323a012 build: should@11.1.2 2017-01-21 00:59:29 -05:00
Douglas Christopher Wilson
e73913b583 build: mocha@3.2.0 2017-01-21 00:46:28 -05:00
Douglas Christopher Wilson
ddc93aa0e2 deps: content-disposition@0.5.2 2017-01-21 00:39:46 -05:00
Zachary Lester
6723b4419a tests: add test for res.sendFile "cacheContol" option
closes #3061
2017-01-21 00:33:29 -05:00
SeongHeon Kim
d1d9631b97 docs: remove link to missing section
closes #3179
2017-01-21 00:26:49 -05:00
Deniz Tetik
1a17888073 docs: fix minor grammatical error
closes #3178
2017-01-21 00:25:47 -05:00
Douglas Christopher Wilson
f6dca56e72 build: istanbul@0.4.5 2016-12-03 00:08:46 -05:00
Douglas Christopher Wilson
6210e47cb6 build: after@0.8.2 2016-12-03 00:04:47 -05:00
Douglas Christopher Wilson
1bcc9b1236 build: Node.js@6.9 2016-12-02 22:19:04 -05:00
Douglas Christopher Wilson
421ad5aaaa build: Node.js@5.12 2016-12-02 22:12:33 -05:00
Douglas Christopher Wilson
505f8482f2 build: Node.js@4.6 2016-12-02 22:09:46 -05:00
Vishvajit Pathak
bd47aeb88d tests: fix typos in test descriptions
closes #3129
closes #3130
2016-11-18 13:47:28 -05:00
Hamza
305f982bd7 exapmples: use path.join to concat paths
closes #3046
2016-07-31 22:14:05 +10:00
Douglas Christopher Wilson
9375a9afa9 4.14.0 2016-06-16 11:03:44 -04:00
Douglas Christopher Wilson
14cf9c5636 deps: update example dependencies 2016-06-15 18:16:08 -04:00
Douglas Christopher Wilson
605983fd0e build: should@9.0.2 2016-06-15 18:13:30 -04:00
Douglas Christopher Wilson
e06766c573 deps: finalhandler@0.5.0 2016-06-15 18:12:19 -04:00
Douglas Christopher Wilson
76eaa326ee Encode URL in res.location/res.redirect if not already encoded
fixes #2897
fixes #3003
2016-06-13 23:23:29 -04:00
Douglas Christopher Wilson
c12cc88392 build: support Node.js 6.x 2016-06-13 22:51:07 -04:00
Douglas Christopher Wilson
23c22ce3fe build: support Node.js 5.x 2016-06-13 22:50:18 -04:00
Douglas Christopher Wilson
791cabf939 deps: serve-static@~1.11.1 2016-06-12 22:38:20 -04:00
Douglas Christopher Wilson
fc40702cb7 deps: send@0.14.1 2016-06-12 22:33:44 -04:00
Douglas Christopher Wilson
c762b16f62 Improve error with invalid arguments to req.get()
fixes #2993
2016-06-03 00:07:34 -04:00
Douglas Christopher Wilson
5d642af8c3 Add "options" argument to req.range 2016-06-01 19:13:36 -04:00
Douglas Christopher Wilson
7fcf1d7d5b docs: update the req.range jsdoc comment 2016-06-01 19:04:02 -04:00
Douglas Christopher Wilson
7ee41cc23f deps: range-parser@~1.2.0 2016-06-01 18:54:11 -04:00
Douglas Christopher Wilson
8ddab697cc build: supertest@1.2.0 2016-06-01 17:31:10 -04:00
Douglas Christopher Wilson
d038689658 build: should@9.0.0 2016-06-01 17:27:06 -04:00
Douglas Christopher Wilson
c9531ac1f1 build: mocha@2.5.3 2016-06-01 17:24:08 -04:00
Douglas Christopher Wilson
98224d2c4f build: ejs@2.4.2 2016-06-01 17:22:15 -04:00
huaoguo
2e1284beb6 Fix Windows absolute path check using forward slashes
closes #3017
2016-06-01 16:47:03 -04:00
Douglas Christopher Wilson
999546dfde deps: qs@6.2.0 2016-05-31 14:28:20 -04:00
Douglas Christopher Wilson
cc25a04d10 deps: type-is@~1.6.13 2016-05-31 14:25:41 -04:00
Benjamin Tan
f90f9dde3f Improve performance for res.json/res.jsonp in most cases
closes #2900
2016-05-31 00:32:48 -04:00
Ángel Sanz
b69b7605b0 perf: use strict equality when possible
closes #2722
2016-05-31 00:25:34 -04:00
Douglas Christopher Wilson
c6039af39d deps: proxy-addr@~1.1.2 2016-05-31 00:12:54 -04:00
Douglas Christopher Wilson
bdf604a77e deps: cookie@0.3.1 2016-05-31 00:08:16 -04:00
Douglas Christopher Wilson
76c56d1ab8 deps: vary@~1.1.0 2016-05-29 14:25:27 -04:00
Douglas Christopher Wilson
2cf830b29e deps: content-type@~1.0.2 2016-05-23 23:18:41 -04:00
Douglas Christopher Wilson
e5502690d2 deps: accepts@~1.3.3 2016-05-23 23:15:52 -04:00
Douglas Christopher Wilson
31dd549f35 tests: add test for dispatching to empty route 2016-05-23 23:03:13 -04:00
Douglas Christopher Wilson
e3dd191d54 examples: escape HTML in markdown example 2016-05-23 23:00:43 -04:00
Douglas Christopher Wilson
fd48bfe8fe build: should@8.4.0 2016-05-23 22:47:25 -04:00
Douglas Christopher Wilson
d7ae24228d build: mocha@2.5.1 2016-05-23 22:44:48 -04:00
Douglas Christopher Wilson
992cd085fb build: istanbul@0.4.3 2016-05-23 22:41:26 -04:00
Douglas Christopher Wilson
20a25489de build: ejs@2.4.1 2016-05-23 22:39:59 -04:00
Douglas Christopher Wilson
741a5aac9c build: cache node_modules on CI 2016-05-23 22:12:31 -04:00
Rand McKinney
3d56e7374d docs: update location of expressjs.com repo
closes #2995
2016-05-12 20:23:54 -04:00
Douglas Christopher Wilson
12bc16e72f tests: use supertest to check response header values
closes #2983
closes #2992
2016-05-11 08:50:38 +02:00
Douglas Christopher Wilson
8931b2311a build: Node.js@4.4 2016-05-10 12:42:16 -04:00
Linus Unnebäck
bb84cf955f tests: add test for signed cookie without secret
closes #2986
2016-05-10 11:54:52 -04:00
Mikeal Rogers
f3d99a4fdb docs: add base contributing guide
closes #2918
2016-03-01 18:55:01 -05:00
Muhammad Saqib
dd2b897774 examples: comment the usage of process.nextTick
closes #2903
closes #2908
2016-02-24 21:58:50 -05:00
Sian January
4bcbf67482 docs: add branch & fork steps to contributing documentation
closes #2881
2016-02-10 18:35:54 -05:00
Andy Fleming
b5a280111f Fix jsdoc comment for res.get
closes #2882
2016-02-10 18:32:51 -05:00
Douglas Christopher Wilson
05136550c7 docs: fix some links messed up from repository move commit
closes #2861
closes #2867
2016-02-10 18:21:46 -05:00
Douglas Christopher Wilson
193bed2649 4.13.4 2016-01-21 21:10:45 -05:00
Douglas Christopher Wilson
e7a02f6a25 build: move repository to expressjs 2016-01-21 20:59:53 -05:00
Douglas Christopher Wilson
6847405974 deps: parseurl@~1.3.1 2016-01-20 00:58:09 -05:00
Douglas Christopher Wilson
f627ca8d0b deps: serve-static@~1.10.2 2016-01-20 00:56:56 -05:00
Douglas Christopher Wilson
e83eab85e4 deps: methods@~1.1.2 2016-01-17 22:17:13 -05:00
Douglas Christopher Wilson
1589ce2153 deps: merge-descriptors@1.0.1 2016-01-17 18:51:24 -05:00
Douglas Christopher Wilson
547ea368c2 deps: content-disposition@0.5.1 2016-01-17 18:00:59 -05:00
Douglas Christopher Wilson
8eee818e0b build: istanbul@0.4.2 2016-01-16 23:58:27 -05:00
Douglas Christopher Wilson
7c8456fcde deps: depd@~1.1.0 2016-01-16 23:57:07 -05:00
Douglas Christopher Wilson
53ee474c44 deps: send@0.13.1 2016-01-16 23:56:09 -05:00
Douglas Christopher Wilson
bd118c47df deps: serve-static@~1.10.1 2016-01-16 23:54:41 -05:00
Jordan Larson
f2cf28c2f3 docs: add link to Gitter 2016-01-13 13:44:41 -08:00
Douglas Christopher Wilson
e44f024dab deps: update example dependencies 2015-12-18 15:10:33 -05:00
Douglas Christopher Wilson
2493239192 build: mocha@2.3.4 2015-12-18 15:09:34 -05:00
Douglas Christopher Wilson
c73b1bee51 build: istanbul@0.4.1 2015-12-17 21:02:22 -05:00
Douglas Christopher Wilson
4f8167f23f deps: range-parser@~1.0.3 2015-12-17 20:59:12 -05:00
Douglas Christopher Wilson
c95a1077d2 deps: proxy-addr@~1.0.10 2015-12-17 20:58:41 -05:00
Douglas Christopher Wilson
7d93503914 deps: finalhandler@0.4.1 2015-12-17 20:56:04 -05:00
Douglas Christopher Wilson
2b2a1b28f3 deps: escape-html@~1.0.3 2015-12-17 20:51:32 -05:00
Rand McKinney
4416fb2746 docs: fix link to Security.md in Readme.md
closes #2829
2015-12-15 15:28:59 -05:00
ChALkeR
60f8e77d66 deps: cookie@0.1.5
closes #2799
closes #2800
closes #2801
2015-12-14 23:18:28 -05:00
Douglas Christopher Wilson
23f021a3e1 build: support Node.js 4.x
closes #2751
closes #2754
closes #2757
2015-12-14 23:10:31 -05:00
Young Jae Sim
67116cc5e6 docs: remove link to Korean translation
closes #2820
2015-12-14 23:08:54 -05:00
Rand McKinney
42b944295a Add Security document
closes #2733
closes #2804
2015-12-14 23:06:17 -05:00
Ricardo Bin
7a3b5aea11 tests: add test for res.send() without arguments
closes #2778
closes #2783
2015-11-07 00:25:06 -05:00
Alexander Shemetovsky
e5ec966b2f Fix param definition is jsdoc for app.render
fixes #2741
2015-11-07 00:18:32 -05:00
Douglas Christopher Wilson
5699d64b99 build: ejs@2.3.4 2015-11-07 00:15:39 -05:00
Douglas Christopher Wilson
747fccfb44 build: should@7.1.1 2015-11-06 22:59:46 -05:00
Douglas Christopher Wilson
9665aa2153 build: supertest@1.1.0 2015-11-06 22:57:04 -05:00
Douglas Christopher Wilson
2f37f4b28d build: istanbul@0.4.0 2015-11-06 22:51:09 -05:00
Douglas Christopher Wilson
1a59246746 build: mocha@2.3.3 2015-11-06 22:49:44 -05:00
Douglas Christopher Wilson
963d795d24 build: support io.js 3.x 2015-11-06 22:47:15 -05:00
Douglas Christopher Wilson
2f96412636 build: io.js@2.5 2015-11-06 22:16:06 -05:00
Douglas Christopher Wilson
5a4310e9da build: reduce runtime versions to one per major 2015-11-06 22:09:47 -05:00
Brendan Ashworth
2f8ac6726f tests: fix redirect tests for change in 302 status message
closes #2690
2015-08-03 15:54:03 -04:00
Douglas Christopher Wilson
ef7ad681b2 4.13.3 2015-08-03 01:02:22 -04:00
Douglas Christopher Wilson
11a77a3fff Fix inner numeric indices incorrectly altering parent req.params 2015-08-03 01:01:16 -04:00
Douglas Christopher Wilson
ee90042d0c Fix infinite loop condition using mergeParams: true 2015-08-03 00:50:48 -04:00
Douglas Christopher Wilson
97b2d70d8a 4.13.2 2015-07-31 17:09:15 -04:00
Douglas Christopher Wilson
a4fcd91084 deps: update example dependencies 2015-07-31 17:03:30 -04:00
Douglas Christopher Wilson
a559ca2d58 build: istanbul@0.3.17 2015-07-31 17:02:57 -04:00
Douglas Christopher Wilson
c398a9903d deps: type-is@~1.6.6 2015-07-31 17:02:10 -04:00
Douglas Christopher Wilson
1cea9cedec deps: accepts@~1.2.12 2015-07-31 17:01:35 -04:00
Blake Embrey
e33c5035bb deps: path-to-regexp@0.1.7
closes #2717
2015-07-31 16:58:57 -04:00
Douglas Christopher Wilson
9848645a8e Merge tag '3.21.2' 2015-07-31 16:56:22 -04:00
Douglas Christopher Wilson
cb59086305 3.21.2 2015-07-31 16:15:06 -04:00
Douglas Christopher Wilson
ce087e559e build: marked@0.3.5 2015-07-31 16:13:41 -04:00
Douglas Christopher Wilson
93dd15cd61 deps: connect@2.30.2 2015-07-31 16:13:09 -04:00
Douglas Christopher Wilson
659c0b154c deps: update example dependencies 2015-07-28 23:26:31 -04:00
Douglas Christopher Wilson
09c80bf823 deps: array-flatten@1.1.1 2015-07-28 23:24:00 -04:00
Douglas Christopher Wilson
b53feaa1d8 deps: vary@~1.0.1 2015-07-27 22:12:39 -04:00
Douglas Christopher Wilson
d51d1ea57a build: ejs@2.3.3 2015-07-27 22:11:54 -04:00
Douglas Christopher Wilson
fc95112145 build: should@7.0.2 2015-07-27 22:09:34 -04:00
Douglas Christopher Wilson
de7ffca33f tests: add test for matching route after error 2015-07-24 21:36:56 -04:00
Douglas Christopher Wilson
2ac2509854 4.13.1 2015-07-06 01:38:44 -04:00
Douglas Christopher Wilson
def241f91f build: io.js@2.3 2015-07-06 01:36:51 -04:00
Douglas Christopher Wilson
a48c55896b deps: update example dependencies 2015-07-06 01:21:26 -04:00
Douglas Christopher Wilson
7bea53b92b deps: qs@4.0.0 2015-07-06 01:20:09 -04:00
Douglas Christopher Wilson
3314f767e1 deps: accepts@~1.2.10 2015-07-06 01:00:12 -04:00
Douglas Christopher Wilson
2870add230 deps: type-is@~1.6.4 2015-07-06 00:59:27 -04:00
Douglas Christopher Wilson
1f906d4ffb Merge tag '3.21.1' 2015-07-06 00:57:49 -04:00
Douglas Christopher Wilson
3c0ff8133b 3.21.1 2015-07-06 00:53:25 -04:00
Douglas Christopher Wilson
f247a4182f deps: basic-auth@~1.0.3 2015-07-06 00:39:42 -04:00
Douglas Christopher Wilson
71d56db947 build: ejs@2.3.2 2015-07-06 00:39:06 -04:00
Douglas Christopher Wilson
3ec7cca550 deps: connect@2.30.1 2015-07-06 00:38:10 -04:00
Douglas Christopher Wilson
6c7a367338 4.13.0 2015-06-21 01:46:44 -04:00
Douglas Christopher Wilson
f73ff92430 build: support io.js 2.x 2015-06-20 19:20:52 -04:00
Douglas Christopher Wilson
2a455890b9 Add settings to debug output
closes #2675
2015-06-20 16:21:12 -04:00
Douglas Christopher Wilson
9302acc5e4 perf: remove argument reassignments in routing 2015-06-20 16:13:59 -04:00
Douglas Christopher Wilson
5b4d4b4ab1 Add statusCode properties to two errors 2015-06-20 15:27:47 -04:00
Douglas Christopher Wilson
7d6c1e5c5c perf: skip attempting to decode zero length string 2015-06-20 15:23:35 -04:00
Douglas Christopher Wilson
3b3e1fc38a Fix hiding platform issues with decodeURIComponent
closes #2652
2015-06-20 15:20:35 -04:00
Douglas Christopher Wilson
5915894af3 Simplify res.cookie to call res.append 2015-06-20 14:38:30 -04:00
Douglas Christopher Wilson
bb53b20d4c perf: remove argument reassignments in response prototype 2015-06-20 14:36:48 -04:00
Douglas Christopher Wilson
d414a2dc73 perf: remove argument reassignments in request prototype 2015-06-20 13:48:58 -04:00
Douglas Christopher Wilson
f5a240636d perf: isolate app.render try block 2015-06-20 13:36:40 -04:00
Douglas Christopher Wilson
10502480d0 perf: remove argument reassignments in application 2015-06-20 13:31:03 -04:00
Douglas Christopher Wilson
a8a8564459 perf: remove argument reassignments in View 2015-06-20 13:06:08 -04:00
Douglas Christopher Wilson
0634e7e189 tests: add test for rendering extensionless file without view engine 2015-06-20 12:54:52 -04:00
Blake Embrey
60e2008dee deps: path-to-regexp@0.1.6
fixes #2491
fixes #2617
closes #2637
closes #2683
2015-06-19 09:59:33 -04:00
Douglas Christopher Wilson
e66bb4f328 deps: path-to-regexp@0.1.4 2015-06-18 23:15:13 -04:00
Behcet Uyar
24d1c98c0a Fix res.format error when only default provided
fixes #2665
2015-06-18 23:08:34 -04:00
Douglas Christopher Wilson
e71014f522 perf: enable strict mode 2015-06-18 23:01:18 -04:00
Douglas Christopher Wilson
95ad276cad docs: add license comments 2015-06-18 23:00:20 -04:00
Thomas Cort
91731b4b9c perf: use saved reference to http.STATUS_CODES
closes #2602
2015-06-18 22:56:30 -04:00
Douglas Christopher Wilson
9073bb4fbc deps: update example dependencies 2015-06-18 22:45:33 -04:00
Douglas Christopher Wilson
4212efad74 deps: accepts@~1.2.9 2015-06-18 22:43:51 -04:00
Douglas Christopher Wilson
7b86a0ec98 deps: type-is@~1.6.3 2015-06-18 22:42:19 -04:00
Douglas Christopher Wilson
8ad7e8f5e1 deps: on-finished@~2.3.0 2015-06-18 22:41:28 -04:00
Douglas Christopher Wilson
7b7aaf0bf3 deps: finalhandler@0.4.0 2015-06-18 22:39:57 -04:00
Douglas Christopher Wilson
b5f98ab3b3 deps: serve-static@~1.10.0 2015-06-18 22:26:48 -04:00
Deepak Kapoor
f7e94a30bc Use array-flatten module for flattening arrays
closes #2624
2015-06-18 22:15:15 -04:00
Radu Dan
8da51e3acc Fix issue where next('route') in app.param would incorrectly skip values
fixes #2655
2015-06-18 22:14:37 -04:00
Douglas Christopher Wilson
3d2ecdd5fa Merge tag '3.21.0' 2015-06-18 22:10:21 -04:00
Alexander Marenin
fce3d14b5c docs: update return types for req.accept*()
closes #2663
2015-06-18 22:05:57 -04:00
Phat
4b70375d22 docs: update res.set jsdoc
closes #2600
2015-06-18 22:04:41 -04:00
Douglas Christopher Wilson
115dbe1a4d 3.21.0 2015-06-18 21:14:56 -04:00
Douglas Christopher Wilson
4729685912 deps: fresh@0.3.0 2015-06-18 20:56:48 -04:00
Douglas Christopher Wilson
14b849246e deps: send@0.13.0 2015-06-18 20:56:03 -04:00
Douglas Christopher Wilson
c8d61b6269 deps: etag@~1.7.0
fixes #2667
2015-06-18 20:54:26 -04:00
Douglas Christopher Wilson
0fbf2078e1 deps: escape-html@1.0.2 2015-06-18 20:36:48 -04:00
Douglas Christopher Wilson
77402110b9 deps: cookie@0.1.3 2015-06-18 20:35:56 -04:00
Douglas Christopher Wilson
5207b99e08 deps: basic-auth@1.0.2 2015-06-18 20:34:04 -04:00
Douglas Christopher Wilson
92b5fa8c53 build: should@7.0.1 2015-06-18 20:10:16 -04:00
Douglas Christopher Wilson
62dfa792b2 deps: connect@2.30.0 2015-06-18 20:08:32 -04:00
Douglas Christopher Wilson
29f51c67a6 docs: fix typos in history
closes #2676
closes #2677
closes #2678
2015-06-17 01:24:21 -04:00
Douglas Christopher Wilson
a20a9a1a2e deps: mkdirp@0.5.1 2015-06-17 01:21:20 -04:00
Douglas Christopher Wilson
9ae08f932e build: should@6.0.3 2015-06-17 01:17:42 -04:00
Douglas Christopher Wilson
e9c9f95ade 4.12.4 2015-05-18 00:38:34 -04:00
Douglas Christopher Wilson
4952127f5b deps: etag@~1.6.0 2015-05-18 00:24:03 -04:00
Douglas Christopher Wilson
18c30d46aa deps: update example dependencies 2015-05-18 00:21:33 -04:00
Douglas Christopher Wilson
2efe7da0a0 deps: accepts@~1.2.7 2015-05-18 00:19:43 -04:00
Douglas Christopher Wilson
1255bca352 deps: on-finished@~2.2.1 2015-05-18 00:18:19 -04:00
Douglas Christopher Wilson
d84bdd6e7d deps: qs@2.4.2 2015-05-18 00:17:10 -04:00
Douglas Christopher Wilson
57252060b2 deps: type-is@~1.6.2 2015-05-18 00:16:14 -04:00
Douglas Christopher Wilson
cd52263d23 deps: finalhandler@0.3.6 2015-05-18 00:15:11 -04:00
Douglas Christopher Wilson
13300f4833 deps: serve-static@~1.9.3 2015-05-18 00:13:48 -04:00
Douglas Christopher Wilson
62d5c38575 Merge tag '3.20.3' 2015-05-18 00:12:01 -04:00
Douglas Christopher Wilson
b149430114 3.20.3 2015-05-18 00:04:41 -04:00
Douglas Christopher Wilson
057898bbe8 docs: update badges 2015-05-18 00:03:54 -04:00
Douglas Christopher Wilson
630c650c3e deps: debug@~2.2.0 2015-05-17 23:54:59 -04:00
Douglas Christopher Wilson
ee2e4f17bb deps: should@6.0.1 2015-05-17 23:53:35 -04:00
Douglas Christopher Wilson
7df8fa3be5 deps: supertest@1.0.1 2015-05-17 23:44:09 -04:00
Douglas Christopher Wilson
96b4a76382 deps: depd@~1.0.1 2015-05-17 23:38:35 -04:00
Douglas Christopher Wilson
519f655f17 deps: send@0.12.3 2015-05-17 21:07:06 -04:00
Douglas Christopher Wilson
f7455227e0 deps: proxy-addr@~1.0.8 2015-05-17 21:04:02 -04:00
Douglas Christopher Wilson
c90de122c8 deps: mocha@2.2.5 2015-05-17 20:59:02 -04:00
Douglas Christopher Wilson
cac867da84 deps: istanbul@0.3.9 2015-05-17 20:58:21 -04:00
Douglas Christopher Wilson
d0e8ac795d deps: connect@2.29.2 2015-05-17 20:56:52 -04:00
Douglas Christopher Wilson
6d43bacb46 build: io.js@1.8 2015-05-01 22:24:05 -04:00
Ignacio Carbajo
ea6e4d3b6f tests: add a missing test description
closes #2631
2015-05-01 22:12:09 -04:00
Douglas Christopher Wilson
8dd1b3a618 build: io.js@1.6 2015-04-11 09:59:44 -04:00
Douglas Christopher Wilson
ab3e7b2465 examples: remove problematic file from download example
closes #2393
2015-04-11 09:54:09 -04:00
Alex Dixon
bbcc1e1f52 examples: fix route-separation example's dev logger
closes #2599
2015-03-19 22:35:49 -04:00
Igor Mozharovsky
2f8a69b710 docs: fix typo in readme
closes #2598
2015-03-18 14:46:29 -04:00
Douglas Christopher Wilson
f56463f8bf 4.12.3 2015-03-17 10:59:48 -04:00
Douglas Christopher Wilson
c894c84e4a build: support io.js 1.x
closes #2539
2015-03-17 02:09:39 -04:00
Douglas Christopher Wilson
4597e118ae deps: update example dependencies 2015-03-17 02:02:23 -04:00
Douglas Christopher Wilson
8ddf158d89 deps: qs@2.4.1 2015-03-17 02:00:56 -04:00
Douglas Christopher Wilson
d0a830bb42 deps: accepts@~1.2.5 2015-03-17 02:00:03 -04:00
Douglas Christopher Wilson
07217205bb deps: type-is@~1.6.1 2015-03-17 01:59:10 -04:00
Douglas Christopher Wilson
9e3727bb23 deps: finalhandler@0.3.4 2015-03-17 01:58:25 -04:00
Douglas Christopher Wilson
410f561b1b deps: serve-static@~1.9.2 2015-03-17 01:57:36 -04:00
Douglas Christopher Wilson
40f4ac3cb3 Merge tag '3.20.2' 2015-03-17 01:52:23 -04:00
Yang Wang
01e059ca74 examples: add missing cookie-session module
fixes #2589
2015-03-17 01:45:03 -04:00
Phat
1114ca1ab6 tests: fix assert usage mistake
fixes #2592
2015-03-17 01:19:38 -04:00
Roman Zubenko
9d16bae682 docs: fix typo in readme
closes #2584
2015-03-17 01:18:59 -04:00
Douglas Christopher Wilson
011e5dc241 3.20.2 2015-03-17 01:03:53 -04:00
Douglas Christopher Wilson
389ab1b19f tests: add test for cookie-sessions example 2015-03-17 01:02:08 -04:00
Douglas Christopher Wilson
279c8bbec3 deps: proxy-addr@~1.0.7 2015-03-17 00:47:15 -04:00
Douglas Christopher Wilson
6744f811b4 deps: debug@~2.1.3 2015-03-17 00:25:00 -04:00
Douglas Christopher Wilson
d7a6d709af deps: merge-descriptors@1.0.0 2015-03-17 00:23:23 -04:00
Douglas Christopher Wilson
ff44e0f9ae deps: send@0.12.2 2015-03-17 00:21:58 -04:00
Douglas Christopher Wilson
100e50f23d deps: connect@2.29.1 2015-03-17 00:17:34 -04:00
Douglas Christopher Wilson
20c040db22 deps: istanbul@0.3.8 2015-03-17 00:15:07 -04:00
Douglas Christopher Wilson
5d8a7a610f deps: should@~5.2.0 2015-03-17 00:14:09 -04:00
Douglas Christopher Wilson
d34d60ce92 deps: mocha@~2.2.1 2015-03-17 00:13:14 -04:00
Douglas Christopher Wilson
dee9fbbbda 4.12.2 2015-03-03 00:06:24 -05:00
Douglas Christopher Wilson
7e0afa8268 Fix regression where "Request aborted" is logged using res.sendFile
closes #2571
2015-03-02 13:11:31 -05:00
Douglas Christopher Wilson
1e6d2654a2 4.12.1 2015-03-01 19:11:02 -05:00
Douglas Christopher Wilson
14a58759c3 Fix ECONNRESET errors from res.sendFile usage
fixes #2571
2015-03-01 17:28:48 -05:00
Douglas Christopher Wilson
dbc61fc191 Fix wrong code on aborted connections from res.sendFile 2015-03-01 17:27:50 -05:00
Douglas Christopher Wilson
31cb541b88 Fix constructing application with non-configurable prototype properties
fixes #2561
2015-03-01 16:33:09 -05:00
Douglas Christopher Wilson
7ee56bbe9c build: skip unnecessary depdency in AppVeyor 2015-02-28 23:31:27 -05:00
Douglas Christopher Wilson
cd6df7699d Merge tag '3.20.1' 2015-02-28 23:29:23 -05:00
Douglas Christopher Wilson
b2311c7402 3.20.1 2015-02-28 23:16:27 -05:00
Douglas Christopher Wilson
9ca0c66e23 build: skip unnecessary dependency in Travis CI 2015-02-28 22:41:01 -05:00
Douglas Christopher Wilson
ef71373fa3 deps: istanbul@0.3.6 2015-02-28 22:39:55 -05:00
Douglas Christopher Wilson
5873d335bd deps: ejs@2.3.1 2015-02-28 22:39:06 -05:00
Douglas Christopher Wilson
2e0f5e7817 Fix req.host when using "trust proxy" hops count 2015-02-28 21:32:51 -05:00
Paul Serby
20aa12616a Fix req.protocol/req.secure when using "trust proxy" hops count
fixes #2569
closes #2570
2015-02-28 21:29:43 -05:00
Douglas Christopher Wilson
bb4703e199 deps: remove un-used devDependency 2015-02-28 21:06:03 -05:00
Douglas Christopher Wilson
51f960f297 4.12.0 2015-02-23 00:56:49 -05:00
Douglas Christopher Wilson
adb6069bd0 deps: ejs@2.3.1 2015-02-23 00:27:17 -05:00
Seth Krasnianski
8fe5fd89c6 tests: fix error-handling typo
closes #2557
2015-02-22 22:30:22 -05:00
Douglas Christopher Wilson
fa546bff85 deps: should@~5.0.1 2015-02-21 15:10:12 -05:00
Douglas Christopher Wilson
1507757f49 deps: istanbul@0.3.6 2015-02-20 19:09:56 -05:00
Douglas Christopher Wilson
028abf5d70 build: add AppVeyor 2015-02-18 23:11:45 -05:00
Douglas Christopher Wilson
3882ba4ba5 docs: update badges 2015-02-18 23:09:47 -05:00
Dmitriy
24fce9deb3 examples: fixes to mvc example
closes #2534
2015-02-18 23:03:24 -05:00
Elvin Yung
9adfc2d586 Fix typos in req.accepts jsdoc
closes #2527
2015-02-18 22:59:49 -05:00
Douglas Christopher Wilson
53e5991dd1 tests: add extra setCharset tests 2015-02-18 22:57:50 -05:00
Douglas Christopher Wilson
9a8cf77c91 deps: update example dependencies 2015-02-18 22:51:18 -05:00
Douglas Christopher Wilson
e56141a7a5 deps: jade@~1.9.2 2015-02-18 22:49:12 -05:00
Douglas Christopher Wilson
ce1abd9f26 deps: serve-static@~1.9.1 2015-02-18 22:48:25 -05:00
Douglas Christopher Wilson
e03ed050ef deps: type-is@~1.6.0 2015-02-18 22:46:34 -05:00
Douglas Christopher Wilson
117d0c9796 deps: accepts@~1.2.4 2015-02-18 22:36:20 -05:00
Douglas Christopher Wilson
531f024e48 Merge tag '3.20.0' 2015-02-18 22:33:47 -05:00
Douglas Christopher Wilson
85755e32d9 3.20.0 2015-02-18 21:25:55 -05:00
Douglas Christopher Wilson
b40e74d6b6 Fix "trust proxy" setting to inherit when app is mounted
fixes #2550
fixes #2551
2015-02-18 00:59:56 -05:00
Douglas Christopher Wilson
eaf3318dd3 Generate ETags for all request responses
closes #2546
2015-02-18 00:12:28 -05:00
Douglas Christopher Wilson
e1057bd7fd build: support Node.js 0.12
closes #2538
2015-02-17 22:52:23 -05:00
Douglas Christopher Wilson
f22937f3d1 Use content-type to parse Content-Type headers 2015-02-17 22:49:24 -05:00
Douglas Christopher Wilson
69a4869db0 deps: should@~5.0.0 2015-02-17 22:43:38 -05:00
Douglas Christopher Wilson
c2a6c8d338 deps: send@0.12.1 2015-02-17 22:42:02 -05:00
Douglas Christopher Wilson
2ce05047f8 deps: cookie-signature@1.0.6 2015-02-17 22:40:51 -05:00
Douglas Christopher Wilson
829fa34581 build: use Travis CI container infrastructure 2015-02-17 22:37:28 -05:00
Douglas Christopher Wilson
3610fdce36 deps: connect@2.29.0 2015-02-17 22:32:18 -05:00
Douglas Christopher Wilson
ca480d7043 tests: improve res.download tests 2015-02-16 17:54:36 -05:00
Douglas Christopher Wilson
63ab25579b 4.11.2 2015-02-01 15:39:08 -05:00
Douglas Christopher Wilson
13c07237fe deps: update example dependencies 2015-02-01 15:27:48 -05:00
Douglas Christopher Wilson
f5d485235e deps: accepts@~1.2.3 2015-02-01 15:26:04 -05:00
Vladimir Grinenko
72d35b6b4a Fix typo in jsdoc description
closes #2514
2015-02-01 15:24:48 -05:00
Douglas Christopher Wilson
c73d7650b5 Merge tag '3.19.2' 2015-02-01 15:23:53 -05:00
Douglas Christopher Wilson
86328767fe 3.19.2 2015-02-01 15:15:53 -05:00
Douglas Christopher Wilson
e497d068a1 deps: marked@0.3.3 2015-02-01 14:58:19 -05:00
Douglas Christopher Wilson
926a71f5ac deps: should@~4.6.2 2015-02-01 14:56:18 -05:00
Douglas Christopher Wilson
55f5a2dc8d deps: proxy-addr@~1.0.6 2015-02-01 14:55:42 -05:00
Douglas Christopher Wilson
fe435e497e deps: connect@2.28.3 2015-02-01 14:54:46 -05:00
Ivan Fraixedes
fea768dbcc Fix an incorrect @api jsdoc
closes #2522
2015-01-31 20:43:36 -05:00
Kevin Shay
2ccb6cf350 Fix res.redirect double-calling res.end for HEAD requests
fixes #2521
2015-01-31 17:29:10 -05:00
Douglas Christopher Wilson
0b62f74a7f deps: type-is@~1.5.6 2015-01-31 17:26:35 -05:00
Douglas Christopher Wilson
45ebb6cdf4 4.11.1 2015-01-21 03:31:11 -05:00
Douglas Christopher Wilson
96f47432a5 deps: update example dependencies 2015-01-21 03:30:16 -05:00
Douglas Christopher Wilson
41f8435d32 tests: fix failing test on Node.js 0.11.15 2015-01-21 03:28:57 -05:00
Douglas Christopher Wilson
b275613d3a deps: serve-static@~1.8.1 2015-01-21 03:25:25 -05:00
Douglas Christopher Wilson
82689d68cf Merge tag '3.19.1' 2015-01-21 03:24:31 -05:00
Douglas Christopher Wilson
0c567b3282 3.19.1 2015-01-21 03:18:16 -05:00
Douglas Christopher Wilson
855176b633 tests: remove more mocking uses 2015-01-21 03:17:30 -05:00
Douglas Christopher Wilson
b95f2ee820 deps: should@~4.6.1 2015-01-21 02:14:27 -05:00
Douglas Christopher Wilson
ae92db98f3 deps: ejs@2.1.4 2015-01-21 02:13:17 -05:00
Douglas Christopher Wilson
0b25547ca0 deps: send@0.11.1 2015-01-21 02:05:03 -05:00
Douglas Christopher Wilson
548f2865e2 deps: connect@2.28.2 2015-01-21 02:03:28 -05:00
Douglas Christopher Wilson
40f7a8eaa2 4.11.0 2015-01-13 22:51:55 -05:00
Douglas Christopher Wilson
9434ad39e1 deps: update example dependencies 2015-01-13 22:19:33 -05:00
Douglas Christopher Wilson
7d983c94c7 deps: serve-static@~1.8.0 2015-01-13 22:18:02 -05:00
Douglas Christopher Wilson
0b1cacff03 deps: accepts@~1.2.2 2015-01-13 22:16:00 -05:00
Douglas Christopher Wilson
b809498cf8 Merge tag '3.19.0' 2015-01-13 22:14:26 -05:00
Douglas Christopher Wilson
f6f78e5f02 Add res.append(field, val) to append headers
closes #2455
2015-01-13 21:07:00 -05:00
Douglas Christopher Wilson
591e89ed18 Deprecate app.param(fn)
closes #2429
2015-01-13 19:28:10 -05:00
Douglas Christopher Wilson
1616079a2d Improve deprecation message for router.param() 2015-01-13 19:27:17 -05:00
Douglas Christopher Wilson
4db51fbeba Deprecate req.param()
closes #2440
2015-01-13 19:17:33 -05:00
Douglas Christopher Wilson
ec8daf0e7b Match routes iteratively to prevent stack overflows
fixes #2412
2015-01-13 15:33:54 -05:00
Douglas Christopher Wilson
5312a990b9 Fix res.sendFile not always detecting aborted connection
fixes #2489
2015-01-13 15:01:32 -05:00
Douglas Christopher Wilson
935f05bc84 Fix OPTIONS responses to include the HEAD method properly
fixes #2459
2015-01-13 13:26:19 -05:00
Douglas Christopher Wilson
fc4eb6dae0 Deprecate leading colon in name for app.param
closes #2430
2015-01-13 12:55:22 -05:00
Douglas Christopher Wilson
08939683c7 4.10.8 2015-01-13 12:38:09 -05:00
Douglas Christopher Wilson
55699bee8f deps: update example dependencies 2015-01-12 18:57:16 -05:00
Douglas Christopher Wilson
dab9222942 Fix crash from error within OPTIONS response handler
fixes #2494
2015-01-12 18:00:49 -05:00
Sung Kim
4070dabe53 Fix typo in comment
closes #2493
2015-01-11 12:14:00 -05:00
Douglas Christopher Wilson
a365864229 deps: proxy-addr@~1.0.5 2015-01-11 12:09:34 -05:00
Douglas Christopher Wilson
ee3f2b073c 3.19.0 2015-01-09 01:07:12 -05:00
Douglas Christopher Wilson
34b6385dc3 deps: debug@~2.1.1 2015-01-09 01:05:41 -05:00
Douglas Christopher Wilson
11529a2ea0 Fix OPTIONS responses to include the HEAD method property
fixes #2459
2015-01-08 23:30:42 -05:00
Douglas Christopher Wilson
b0f8809e3d deps: commander@2.6.0 2015-01-08 22:23:04 -05:00
Douglas Christopher Wilson
ec1175daa3 Use readline for prompt in express(1) 2015-01-08 22:21:50 -05:00
Douglas Christopher Wilson
3a1d9b8289 deps: ejs@2.0.8 2015-01-08 22:17:19 -05:00
Douglas Christopher Wilson
192be8fea3 deps: send@0.11.0 2015-01-08 22:15:53 -05:00
Douglas Christopher Wilson
1afcff955b deps: proxy-addr@~1.0.5 2015-01-08 22:14:46 -05:00
Douglas Christopher Wilson
224fe05697 deps: methods@~1.1.1 2015-01-08 21:31:32 -05:00
Douglas Christopher Wilson
2dd332b491 deps: mocha@~2.1.0 2015-01-08 21:25:17 -05:00
Douglas Christopher Wilson
33e4193f45 deps: should@~4.4.4 2015-01-08 21:24:28 -05:00
Douglas Christopher Wilson
c163d2f33d deps: connect@2.28.1 2015-01-08 21:18:56 -05:00
Douglas Christopher Wilson
a715ba6be4 docs: Gittip is now Gratipay 2015-01-08 17:06:08 -05:00
Douglas Christopher Wilson
ff5e96c88b 4.10.7 2015-01-04 19:33:31 -05:00
Nick Mandel
d842647217 docs: readme tweaks
closes #2471
2015-01-04 19:17:12 -05:00
Douglas Christopher Wilson
12626aed35 Fix Allow header for OPTIONS to not contain duplicate methods
fixes #2458
2015-01-04 19:07:21 -05:00
Douglas Christopher Wilson
3387916efc Fix incorrect "Request aborted" for res.sendFile when HEAD or 304
fixes #2481
2015-01-04 18:26:15 -05:00
Douglas Christopher Wilson
f76403b717 deps: type-is@~1.5.5 2015-01-04 17:50:42 -05:00
Douglas Christopher Wilson
2d6faf6da7 deps: serve-static@~1.7.2 2015-01-04 17:49:39 -05:00
Douglas Christopher Wilson
a7227a0964 deps: debug@~2.1.1 2015-01-04 17:47:25 -05:00
Douglas Christopher Wilson
6e9cfa2aea deps: on-finished@~2.2.0 2015-01-04 17:46:41 -05:00
Douglas Christopher Wilson
571ce16405 deps: methods@~1.1.1 2015-01-04 17:42:57 -05:00
Douglas Christopher Wilson
98585d1d0a deps: finalhandler@0.3.3 2015-01-04 17:40:22 -05:00
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
138 changed files with 7089 additions and 2139 deletions

38
.gitignore vendored
View File

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

View File

@@ -1,11 +0,0 @@
.git*
benchmarks/
coverage/
docs/
examples/
support/
test/
testing.js
.DS_Store
.travis.yml
Contributing.md

View File

@@ -1,10 +1,23 @@
language: node_js
node_js:
- "0.10"
- "0.11"
matrix:
allow_failures:
- node_js: "0.11"
fast_finish: true
script: "npm run-script test-travis"
- "0.12"
- "1.8"
- "2.5"
- "3.3"
- "4.7"
- "5.12"
- "6.9"
sudo: false
cache:
directories:
- node_modules
before_install:
# Remove all non-test dependencies
- "npm rm --save-dev connect-redis"
# Update Node.js modules
- "test ! -d node_modules || npm prune"
- "test ! -d node_modules || npm rebuild"
script: "npm run-script test-ci"
after_script: "npm install coveralls@2.10.0 && cat ./coverage/lcov.info | coveralls"

36
Collaborator-Guide.md Normal file
View File

@@ -0,0 +1,36 @@
## Website Issues
Open issues for the expressjs.com website in https://github.com/expressjs/expressjs.com.
## PRs and Code contributions
* Tests must pass.
* Follow existing coding style.
* If you fix a bug, add a test.
## Branches
* Use the `master` branch for bug fixes or minor work that is intended for the current release stream
* Use the correspondingly named branch, e.g. `5.0`, for anything intended for a future release of Express
## Steps for contributing
* [Create an issue](https://github.com/expressjs/express/issues/new) for the bug you want to fix or the feature that you want to add.
* Create your own [fork](https://github.com/expressjs/express) on github, then checkout your fork.
* Write your code in your local copy. It's good practice to create a branch for each new issue you work on, although not compulsory.
* To run the test suite, first install the dependencies by running `npm install`, then run `npm test`.
* If the tests pass, you can commit your changes to your fork and then create a pull request from there. Make sure to reference your issue from the pull request comments by including the issue number e.g. #123.
## 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.

View File

@@ -1,25 +1,92 @@
# Node.js Community Contributing Guide 1.0
## Website Issues
This document describes a very simple process suitable for most projects
in the Node.js ecosystem. Projects are encouraged to adopt this whether they
are hosted in the Node.js Foundation or not.
Issues for the expressjs.com website go here https://github.com/visionmedia/expressjs.com
The goal of this document is to create a contribution process that:
## PRs and Code contributions
* Encourages new contributions.
* Encourages contributors to remain involved.
* Avoids unnecessary processes and bureaucracy whenever possible.
* Creates a transparent decision making process which makes it clear how
contributors can be involved in decision making.
* Tests must pass.
* Follow existing coding style.
* If you fix a bug, add a test.
This document is based on much prior art in the Node.js community, io.js,
and the Node.js project.
## Vocabulary
* A **Contributor** is any individual creating or commenting on an issue or pull request.
* A **Committer** is a subset of contributors who have been given write access to the repository.
* A **TC (Technical Committee)** is a group of committers representing the required technical
expertise to resolve rare disputes.
# Logging Issues
Log an issue for any question or problem you might have. When in doubt, log an issue,
any additional policies about what to include will be provided in the responses. The only
exception is security dislosures which should be sent privately.
Committers may direct you to another repository, ask for additional clarifications, and
add appropriate metadata before the issue is addressed.
Please be courteous and respectful. Every participant is expected to follow the
project's Code of Conduct.
# Contributions
Any change to resources in this repository must be through pull requests. This applies to all changes
to documentation, code, binary files, etc. Even long term committers and TC members must use
pull requests.
No pull request can be merged without being reviewed.
For non-trivial contributions, pull requests should sit for at least 36 hours to ensure that
contributors in other timezones have time to review. Consideration should also be given to
weekends and other holiday periods to ensure active committers all have reasonable time to
become involved in the discussion and review process if they wish.
The default for each contribution is that it is accepted once no committer has an objection.
During review committers may also request that a specific contributor who is most versed in a
particular area gives a "LGTM" before the PR can be merged. There is no additional "sign off"
process for contributions to land. Once all issues brought by committers are addressed it can
be landed by any committer.
In the case of an objection being raised in a pull request by another committer, all involved
committers should seek to arrive at a consensus by way of addressing concerns being expressed
by discussion, compromise on the proposed change, or withdrawal of the proposed change.
If a contribution is controversial and committers cannot agree about how to get it to land
or if it should land then it should be escalated to the TC. TC members should regularly
discuss pending contributions in order to find a resolution. It is expected that only a
small minority of issues be brought to the TC for resolution and that discussion and
compromise among committers be the default resolution mechanism.
# Becoming a Committer
All contributors who land a non-trivial contribution should be on-boarded in a timely manner,
and added as a committer, and be given write access to the repository.
Committers are expected to follow this policy and continue to send pull requests, go through
proper review, and have other committers merge their pull requests.
# TC Process
The TC uses a "consensus seeking" process for issues that are escalated to the TC.
The group tries to find a resolution that has no open objections among TC members.
If a consensus cannot be reached that has no objections then a majority wins vote
is called. It is also expected that the majority of decisions made by the TC are via
a consensus seeking process and that voting is only used as a last-resort.
Resolution may involve returning the issue to committers with suggestions on how to
move forward towards a consensus. It is not expected that a meeting of the TC
will resolve all issues on its agenda during that meeting and may prefer to continue
the discussion happening among the committers.
Members can be added to the TC at any time. Any committer can nominate another committer
to the TC and the TC uses its standard consensus seeking process to evaluate whether or
not to add this new member. Members who do not participate consistently at the level of
a majority of the other members are expected to resign.
## 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.

1436
History.md

File diff suppressed because it is too large Load Diff

View File

@@ -1,6 +1,8 @@
(The MIT License)
Copyright (c) 2009-2014 TJ Holowaychuk <tj@vision-media.ca>
Copyright (c) 2013-2014 Roman Shtylman <shtylman+expressjs@gmail.com>
Copyright (c) 2014-2015 Douglas Christopher Wilson <doug@somethingdoug.com>
Permission is hereby granted, free of charge, to any person obtaining
a copy of this software and associated documentation files (the

115
Readme.md
View File

@@ -1,11 +1,12 @@
[![Express Logo](https://i.cloudup.com/zfY6lL7eFa-3000x3000.png)](https://expressjs.com/)
[![Express Logo](https://i.cloudup.com/zfY6lL7eFa-3000x3000.png)](http://expressjs.com/)
Fast, unopinionated, minimalist web framework for [node](https://nodejs.org).
Fast, unopinionated, minimalist web framework for [node](http://nodejs.org).
[![NPM Version](https://badge.fury.io/js/express.svg)](https://badge.fury.io/js/express)
[![Build Status](https://travis-ci.org/visionmedia/express.svg?branch=master)](https://travis-ci.org/visionmedia/express)
[![Coverage Status](https://img.shields.io/coveralls/visionmedia/express.svg)](https://coveralls.io/r/visionmedia/express)
[![Gittip](https://img.shields.io/gittip/visionmedia.svg)](https://www.gittip.com/visionmedia/)
[![NPM Version][npm-image]][npm-url]
[![NPM Downloads][downloads-image]][downloads-url]
[![Linux Build][travis-image]][travis-url]
[![Windows Build][appveyor-image]][appveyor-url]
[![Test Coverage][coveralls-image]][coveralls-url]
```js
var express = require('express')
@@ -18,14 +19,38 @@ app.get('/', function (req, res) {
app.listen(3000)
```
**PROTIP** Be sure to read [Migrating from 3.x to 4.x](https://github.com/visionmedia/express/wiki/Migrating-from-3.x-to-4.x) as well as [New features in 4.x](https://github.com/visionmedia/express/wiki/New-features-in-4.x).
### Installation
## Installation
```bash
$ npm install express
```
## Features
* Robust routing
* Focus on high performance
* Super-high test coverage
* HTTP helpers (redirection, caching, etc)
* View system supporting 14+ template engines
* Content negotiation
* Executable for generating applications quickly
## 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/expressjs/express/wiki)
* [Google Group](https://groups.google.com/group/express-js) for discussion
* [Gitter](https://gitter.im/expressjs/express) for support and discussion
* [Русскоязычная документация](http://jsman.ru/express/)
**PROTIP** Be sure to read [Migrating from 3.x to 4.x](https://github.com/expressjs/express/wiki/Migrating-from-3.x-to-4.x) as well as [New features in 4.x](https://github.com/expressjs/express/wiki/New-features-in-4.x).
###Security Issues
If you discover a security vulnerability in Express, please see [Security Policies and Procedures](Security.md).
## 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:
@@ -54,16 +79,6 @@ $ npm install
$ npm start
```
## Features
* Robust routing
* HTTP helpers (redirection, caching, etc)
* View system supporting 14+ template engines
* Content negotiation
* Focus on high performance
* Executable for generating applications quickly
* High test coverage
## Philosophy
The Express philosophy is to provide small, robust tooling for HTTP servers, making
@@ -71,57 +86,57 @@ $ npm start
HTTP APIs.
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/visionmedia/consolidate.js),
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/) - [[website repo](https://github.com/visionmedia/expressjs.com)]
* [Github Organization](https://github.com/expressjs) for Official Middleware & Modules
* [#express](https://webchat.freenode.net/?channels=express) on freenode IRC
* Visit the [Wiki](https://github.com/visionmedia/express/wiki)
* [Google Group](https://groups.google.com/group/express-js) for discussion
* [Русскоязычная документация](http://jsman.ru/express/)
* Run express examples [online](https://runnable.com/express)
## Viewing Examples
Clone the Express repo, then install the dev dependencies to install all the example / test suite dependencies:
To view the examples, clone the Express repo and install the dependencies:
```bash
$ git clone git://github.com/visionmedia/express.git --depth 1
$ git clone git://github.com/expressjs/express.git --depth 1
$ cd express
$ npm install
```
Then run whichever example you want:
$ node examples/content-negotiation
```bash
$ node examples/content-negotiation
```
You can also view live examples here:
## Tests
<a href="https://runnable.com/express" target="_blank"><img src="https://runnable.com/external/styles/assets/runnablebtn.png" style="width:67px;height:25px;"></a>
## Running Tests
To run the test suite, first invoke the following command within the repo, installing the development dependencies:
To run the test suite, first install the dependencies, then run `npm test`:
```bash
$ npm install
```
Then run the tests:
```bash
$ npm test
```
### Contributors
## People
* Author: [TJ Holowaychuk](https://github.com/visionmedia)
* Lead Maintainer: [Douglas Christopher Wilson](https://github.com/dougwilson)
* [All Contributors](https://github.com/visionmedia/express/graphs/contributors)
The original author of Express is [TJ Holowaychuk](https://github.com/tj) [![TJ's Gratipay][gratipay-image-visionmedia]][gratipay-url-visionmedia]
### License
The current lead maintainer is [Douglas Christopher Wilson](https://github.com/dougwilson) [![Doug's Gratipay][gratipay-image-dougwilson]][gratipay-url-dougwilson]
[List of all contributors](https://github.com/expressjs/express/graphs/contributors)
## License
[MIT](LICENSE)
[npm-image]: https://img.shields.io/npm/v/express.svg
[npm-url]: https://npmjs.org/package/express
[downloads-image]: https://img.shields.io/npm/dm/express.svg
[downloads-url]: https://npmjs.org/package/express
[travis-image]: https://img.shields.io/travis/expressjs/express/master.svg?label=linux
[travis-url]: https://travis-ci.org/expressjs/express
[appveyor-image]: https://img.shields.io/appveyor/ci/dougwilson/express/master.svg?label=windows
[appveyor-url]: https://ci.appveyor.com/project/dougwilson/express
[coveralls-image]: https://img.shields.io/coveralls/expressjs/express/master.svg
[coveralls-url]: https://coveralls.io/r/expressjs/express?branch=master
[gratipay-image-visionmedia]: https://img.shields.io/gratipay/visionmedia.svg
[gratipay-url-visionmedia]: https://gratipay.com/visionmedia/
[gratipay-image-dougwilson]: https://img.shields.io/gratipay/dougwilson.svg
[gratipay-url-dougwilson]: https://gratipay.com/dougwilson/

43
Security.md Normal file
View File

@@ -0,0 +1,43 @@
# Security Policies and Procedures
This document outlines security procedures and general policies for the Express
project.
* [Reporting a Bug](#reporting-a-bug)
* [Disclosure Policy](#disclosure-policy)
* [Comments on this Policy](#comments-on-this-policy)
## Reporting a Bug
The Express team and community take all security bugs in Express seriously.
Thank you for improving the security of Express. We appreciate your efforts and
responsible disclosure and will make every effort to acknowledge your
contributions.
Report security bugs by emailing the lead maintainer in the Readme.md file.
The lead maintainer will acknowledge your email within 48 hours, and will send a
more detailed response within 48 hours indicating the next steps in handling
your report. After the initial reply to your report, the security team will
endeavor to keep you informed of the progress towards a fix and full
announcement, and may ask for additional information or guidance.
Report security bugs in third-party modules to the person or team maintaining
the module. You can also report a vulnerability through the
[Node Security Project](https://nodesecurity.io/report).
## Disclosure Policy
When the security team receives a security bug report, they will assign it to a
primary handler. This person will coordinate the fix and release process,
involving the following steps:
* Confirm the problem and determine the affected versions.
* Audit code to find any potential similar problems.
* Prepare fixes for all releases still under maintenance. These fixes will be
released as fast as possible to npm.
## Comments on this Policy
If you have suggestions on how this process could be improved please submit a
pull request.

24
appveyor.yml Normal file
View File

@@ -0,0 +1,24 @@
environment:
matrix:
- nodejs_version: "0.10"
- nodejs_version: "0.12"
- nodejs_version: "1.8"
- nodejs_version: "2.5"
- nodejs_version: "3.3"
- nodejs_version: "4.7"
- nodejs_version: "5.12"
- nodejs_version: "6.9"
cache:
- node_modules
install:
- ps: Install-Product node $env:nodejs_version
- npm rm --save-dev connect-redis
- if exist node_modules npm prune
- if exist node_modules npm rebuild
- npm install
build: off
test_script:
- node --version
- npm --version
- npm run test-ci
version: "{build}"

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,31 +0,0 @@
/**
* Module dependencies.
*/
var express = require('../..');
var logger = require('morgan');
var app = express();
app.set('views', __dirname);
app.set('view engine', 'jade');
var pets = [];
var n = 1000;
while (n--) {
pets.push({ name: 'Tobi', age: 2, species: 'ferret' });
pets.push({ name: 'Loki', age: 1, species: 'ferret' });
pets.push({ name: 'Jane', age: 6, species: 'ferret' });
}
app.use(logger('dev'));
app.get('/', function(req, res){
res.render('pets', { pets: pets });
});
/* istanbul ignore next */
if (!module.parent) {
app.listen(3000);
console.log('Express started on port 3000');
}

View File

@@ -1,12 +0,0 @@
style.
body {
padding: 50px;
font: 16px "Helvetica Neue", Helvetica;
}
table
for pet in pets
tr
td= pet.name
td= pet.age
td= pet.species

View File

@@ -2,6 +2,7 @@
* Module dependencies.
*/
var cookieSession = require('cookie-session');
var express = require('../../');
var app = module.exports = express();

View File

@@ -1,48 +0,0 @@
/**
* Module dependencies.
*/
var express = require('../..');
var logger = require('morgan');
var app = express();
var bodyParser = require('body-parser');
var api = express();
// app middleware
app.use(express.static(__dirname + '/public'));
// api middleware
api.use(logger('dev'));
api.use(bodyParser.json());
/**
* 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', 'PUT');
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();
});
/**
* PUT an existing user.
*/
api.put('/user/:id', function(req, res){
console.log(req.body);
res.send(204);
});
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('PUT', 'http://localhost:3001/user/1', false);
req.setRequestHeader('Content-Type', 'application/json');
req.send('{"name":"tobi","species":"ferret"}');
console.log(req.responseText);
</script>
</body>
</html>

View File

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

View File

@@ -8,7 +8,6 @@ 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>');

View File

@@ -9,7 +9,7 @@ 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
@@ -25,7 +25,7 @@ silent || app.use(logger('dev'));
// Routes
app.get('/', function(req, res){
res.render('index.jade');
res.render('index.ejs');
});
app.get('/404', function(req, res, next){
@@ -96,7 +96,6 @@ app.use(function(err, req, res, next){
res.render('500', { error: err });
});
/* istanbul ignore next */
if (!module.parent) {
app.listen(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

@@ -20,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){
@@ -30,6 +31,9 @@ app.get('/', function(req, res){
app.get('/next', function(req, res, next){
// We can also pass exceptions to next()
// The reason for process.nextTick() is to show that
// next() can be called inside an async operation,
// in real life it can be a DB read or HTTP request.
process.nextTick(function(){
next(new Error('oh no!'));
});

View File

@@ -2,9 +2,10 @@
* Module dependencies.
*/
var escapeHtml = require('escape-html');
var express = require('../..');
var fs = require('fs');
var md = require('marked').parse;
var marked = require('marked');
var app = module.exports = express();
@@ -13,15 +14,10 @@ var app = module.exports = express();
app.engine('md', function(path, options, fn){
fs.readFile(path, 'utf8', function(err, str){
if (err) return fn(err);
try {
var html = md(str);
html = html.replace(/\{([^}]+)\}/g, function(_, name){
return options[name] || '';
});
fn(null, html);
} catch(err) {
fn(err);
}
var html = marked.parse(str).replace(/\{([^}]+)\}/g, function(_, name){
return escapeHtml(options[name] || '');
});
fn(null, html);
});
});

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

@@ -4,6 +4,8 @@
var db = require('../../db');
exports.engine = 'ejs';
exports.before = function(req, res, next){
var pet = db.pets[req.params.pet_id];
if (!pet) return next('route');

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="pet[name]" value="<%= pet.name %>"></label>
<input type="submit" value="Update">
</form>
</body>
</html>

View File

@@ -1,6 +0,0 @@
link(rel='stylesheet', href='/style.css')
h1= pet.name
form(action='/pet/#{pet.id}?_method=put', method='post')
label= 'Name: '
input(type='text', name='pet[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

@@ -8,6 +8,7 @@ var fs = require('fs');
module.exports = function(parent, options){
var verbose = options.verbose;
fs.readdirSync(__dirname + '/../controllers').forEach(function(name){
if (!fs.statSync(__dirname + '/../controllers/' + name).isDirectory()) return;
verbose && console.log('\n %s:', name);
var obj = require('./../controllers/' + name);
var name = obj.name || name;
@@ -66,7 +67,7 @@ module.exports = function(parent, options){
app[method](path, obj.before, handler);
verbose && console.log(' %s %s -> before -> %s', method.toUpperCase(), path, key);
} else {
app[method](path, obj[key]);
app[method](path, handler);
verbose && console.log(' %s %s -> %s', method.toUpperCase(), path, key);
}
}

View File

@@ -15,12 +15,20 @@ var users = [
, { name: 'bandit' }
];
// Create HTTP error
function createError(status, message) {
var err = new Error(message);
err.status = status;
return err;
}
// Convert :to and :from to integers
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));
next(createError(400, 'failed to parseInt '+num));
} else {
next();
}
@@ -32,7 +40,7 @@ app.param('user', function(req, res, next, id){
if (req.user = users[id]) {
next();
} else {
next(new Error('failed to find user'));
next(createError(404, 'failed to find user'));
}
});

View File

@@ -7,15 +7,23 @@ 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(logger('dev'));
/* istanbul ignore next */
if (!module.parent) {
app.use(logger('dev'));
}
app.use(methodOverride('_method'));
app.use(cookieParser());
app.use(bodyParser.urlencoded({ extended: true }));
@@ -27,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);

View File

@@ -15,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);
}
};
@@ -40,4 +42,4 @@ exports.update = function(req, res){
req.user.name = user.name;
req.user.email = user.email;
res.redirect('back');
};
};

View File

@@ -47,14 +47,14 @@ 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');
});
/* istanbul ignore next */

View File

@@ -4,6 +4,7 @@
var express = require('../..');
var logger = require('morgan');
var path = require('path');
var app = express();
// log requests
@@ -16,7 +17,7 @@ app.use(logger('dev'));
// that you pass it. In this case "GET /js/app.js"
// will look for "./public/js/app.js".
app.use(express.static(__dirname + '/public'));
app.use(express.static(path.join(__dirname, 'public')));
// if you wanted to "prefix" you may use
// the mounting feature of Connect, for example
@@ -24,13 +25,13 @@ app.use(express.static(__dirname + '/public'));
// The mount-path "/static" is simply removed before
// passing control to the express.static() middleware,
// thus it serves the file correctly by ignoring "/static"
app.use('/static', express.static(__dirname + '/public'));
app.use('/static', express.static(path.join(__dirname, 'public')));
// if for some reason you want to serve files from
// several directories, you can use express.static()
// multiple times! Here we're passing "./public/css",
// this will allow "GET /style.css" instead of "GET /css/style.css":
app.use(express.static(__dirname + '/public/css'));
app.use(express.static(path.join(__dirname, 'public', 'css')));
app.listen(3000);
console.log('listening on port 3000');

View File

@@ -34,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

@@ -23,7 +23,7 @@ app.engine('md', function(str, options, fn){
});
// pointing to a particular github repo to load files from it
app.set('views', 'visionmedia/express');
app.set('views', 'expressjs/express');
// register a new view constructor
app.set('view', GithubView);
@@ -36,7 +36,7 @@ app.get('/', function(req, res){
});
app.get('/Readme.md', function(req, res){
// rendering a view from https://github.com/visionmedia/express/blob/master/Readme.md
// rendering a view from https://github.com/expressjs/express/blob/master/Readme.md
res.render('Readme.md');
});

View File

@@ -9,6 +9,9 @@ function User(name, age, species) {
}
User.all = function(fn){
// process.nextTick makes sure this function API
// behaves in an asynchronous manner, like if it
// was a real DB query to read all users.
process.nextTick(function(){
fn(null, users);
});

View File

@@ -28,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
@@ -49,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/expressjs/express' }
, { name: 'stylus', url: 'http://github.com/learnboost/stylus' }
, { name: 'cluster', url: 'http://github.com/learnboost/cluster' }
];
@@ -93,14 +93,16 @@ app.get('/api/user/:name/repos', function(req, res, next){
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 });
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.send(404, { error: "Lame, can't find that" });
res.status(404);
res.send({ error: "Lame, can't find that" });
});
/* istanbul ignore next */

View File

@@ -1,2 +1,11 @@
/*!
* express
* Copyright(c) 2009-2013 TJ Holowaychuk
* Copyright(c) 2013 Roman Shtylman
* Copyright(c) 2014-2015 Douglas Christopher Wilson
* MIT Licensed
*/
'use strict';
module.exports = require('./lib/express');

View File

@@ -1,9 +1,19 @@
/*!
* express
* Copyright(c) 2009-2013 TJ Holowaychuk
* Copyright(c) 2013 Roman Shtylman
* Copyright(c) 2014-2015 Douglas Christopher Wilson
* MIT Licensed
*/
'use strict';
/**
* Module dependencies.
* @private
*/
var finalhandler = require('finalhandler');
var mixin = require('utils-merge');
var Router = require('./router');
var methods = require('methods');
var middleware = require('./middleware/init');
@@ -12,9 +22,13 @@ 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 flatten = require('array-flatten');
var merge = require('utils-merge');
var resolve = require('path').resolve;
var slice = Array.prototype.slice;
/**
* Application prototype.
@@ -22,6 +36,13 @@ var resolve = require('path').resolve;
var app = exports = module.exports = {};
/**
* Variable for trust proxy inheritance back-compat
* @private
*/
var trustProxyDefaultSymbol = '@@symbol:trust_proxy_default';
/**
* Initialize the server.
*
@@ -29,35 +50,50 @@ var app = exports = module.exports = {};
* - setup default middleware
* - setup route reflection methods
*
* @api private
* @private
*/
app.init = function(){
app.init = function init() {
this.cache = {};
this.settings = {};
this.engines = {};
this.settings = {};
this.defaultConfiguration();
};
/**
* Initialize application configuration.
*
* @api private
* @private
*/
app.defaultConfiguration = function(){
app.defaultConfiguration = function defaultConfiguration() {
var env = process.env.NODE_ENV || 'development';
// default settings
this.enable('x-powered-by');
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);
this.set('trust proxy', false);
// trust proxy inherit back-compat
Object.defineProperty(this.settings, trustProxyDefaultSymbol, {
configurable: true,
value: true
});
debug('booting in %s mode', env);
// inherit protos
this.on('mount', function(parent){
this.on('mount', function onmount(parent) {
// inherit trust proxy
if (this.settings[trustProxyDefaultSymbol] === true
&& typeof parent.settings['trust proxy fn'] === 'function') {
delete this.settings['trust proxy'];
delete this.settings['trust proxy fn'];
}
// inherit protos
this.request.__proto__ = parent.request;
this.response.__proto__ = parent.response;
this.engines.__proto__ = parent.engines;
@@ -95,16 +131,16 @@ app.defaultConfiguration = function(){
* We cannot add the base router in the defaultConfiguration because
* it reads app settings which might be set after that has run.
*
* @api private
* @private
*/
app.lazyrouter = function() {
app.lazyrouter = function lazyrouter() {
if (!this._router) {
this._router = new Router({
caseSensitive: this.enabled('case sensitive routing'),
strict: this.enabled('strict routing')
});
this._router.use(query());
this._router.use(query(this.get('query parser fn')));
this._router.use(middleware.init(this));
}
};
@@ -112,17 +148,17 @@ app.lazyrouter = function() {
/**
* Dispatch a req, res pair into the application. Starts pipeline processing.
*
* If no _done_ callback is provided, then default error handlers will respond
* If no callback is provided, then default error handlers will respond
* in the event of an error bubbling through the stack.
*
* @api private
* @private
*/
app.handle = function(req, res, done) {
app.handle = function handle(req, res, callback) {
var router = this._router;
// final handler
done = done || finalhandler(req, res, {
var done = callback || finalhandler(req, res, {
env: this.get('env'),
onerror: logerror.bind(this)
});
@@ -144,40 +180,62 @@ app.handle = function(req, res, done) {
* If the _fn_ parameter is an express app, then it will be
* mounted at the _route_ specified.
*
* @api public
* @public
*/
app.use = function(route, fn){
var mount_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) mount_app = fn;
while (Array.isArray(arg) && arg.length !== 0) {
arg = arg[0];
}
// restore .app property on req and res
if (mount_app) {
debug('.use app under %s', route);
mount_app.mountpath = 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;
mount_app.handle(req, res, function(err) {
fn.handle(req, res, function (err) {
req.__proto__ = orig.request;
res.__proto__ = orig.response;
next(err);
});
};
}
});
this.lazyrouter();
this._router.use(route, fn);
// mounted an app
if (mount_app) {
mount_app.parent = this;
mount_app.emit('mount', this);
}
// mounted an app
fn.emit('mount', this);
}, this);
return this;
};
@@ -189,10 +247,10 @@ app.use = function(route, fn){
* Routes are isolated middleware stacks for specific paths.
* See the Route api docs for details.
*
* @api public
* @public
*/
app.route = function(path){
app.route = function route(path) {
this.lazyrouter();
return this._router.route(path);
};
@@ -220,7 +278,7 @@ app.route = function(path){
* 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.
@@ -228,13 +286,22 @@ app.route = function(path){
* @param {String} ext
* @param {Function} fn
* @return {app} for chaining
* @api public
* @public
*/
app.engine = function(ext, fn){
if ('function' != typeof fn) throw new Error('callback function required');
if ('.' != ext[0]) ext = '.' + ext;
this.engines[ext] = fn;
app.engine = function engine(ext, fn) {
if (typeof fn !== 'function') {
throw new Error('callback function required');
}
// get file extension
var extension = ext[0] !== '.'
? '.' + ext
: ext;
// store engine
this.engines[extension] = fn;
return this;
};
@@ -247,21 +314,22 @@ app.engine = function(ext, fn){
* @param {String|Array} name
* @param {Function} fn
* @return {app} for chaining
* @api public
* @public
*/
app.param = function(name, fn){
var self = this;
self.lazyrouter();
app.param = function param(name, fn) {
this.lazyrouter();
if (Array.isArray(name)) {
name.forEach(function(key) {
self.param(key, fn);
});
for (var i = 0; i < name.length; i++) {
this.param(name[i], fn);
}
return this;
}
self._router.param(name, fn);
this._router.param(name, fn);
return this;
};
@@ -277,27 +345,37 @@ app.param = function(name, fn){
* @param {String} setting
* @param {*} [val]
* @return {Server} for chaining
* @api public
* @public
*/
app.set = function(setting, val){
app.set = function set(setting, val) {
if (arguments.length === 1) {
// app.get(setting)
return this.settings[setting];
}
debug('set "%s" to %o', setting, val);
// 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':
this.set('query parser fn', compileQueryParser(val));
break;
case 'trust proxy':
debug('compile trust proxy %s', val);
this.set('trust proxy fn', compileTrust(val));
// trust proxy inherit back-compat
Object.defineProperty(this.settings, trustProxyDefaultSymbol, {
configurable: true,
value: false
});
break;
}
@@ -315,10 +393,10 @@ app.set = function(setting, val){
* return value would be "/blog/admin".
*
* @return {String}
* @api private
* @private
*/
app.path = function(){
app.path = function path() {
return this.parent
? this.parent.path() + this.mountpath
: '';
@@ -336,11 +414,11 @@ app.path = function(){
*
* @param {String} setting
* @return {Boolean}
* @api public
* @public
*/
app.enabled = function(setting){
return !!this.set(setting);
app.enabled = function enabled(setting) {
return Boolean(this.set(setting));
};
/**
@@ -355,10 +433,10 @@ app.enabled = function(setting){
*
* @param {String} setting
* @return {Boolean}
* @api public
* @public
*/
app.disabled = function(setting){
app.disabled = function disabled(setting) {
return !this.set(setting);
};
@@ -367,10 +445,10 @@ app.disabled = function(setting){
*
* @param {String} setting
* @return {app} for chaining
* @api public
* @public
*/
app.enable = function(setting){
app.enable = function enable(setting) {
return this.set(setting, true);
};
@@ -379,10 +457,10 @@ app.enable = function(setting){
*
* @param {String} setting
* @return {app} for chaining
* @api public
* @public
*/
app.disable = function(setting){
app.disable = function disable(setting) {
return this.set(setting, false);
};
@@ -392,12 +470,15 @@ app.disable = function(setting){
methods.forEach(function(method){
app[method] = function(path){
if ('get' == method && 1 == arguments.length) return this.set(path);
if (method === 'get' && arguments.length === 1) {
// app.get(setting)
return this.set(path);
}
this.lazyrouter();
var route = this._router.route(path);
route[method].apply(route, [].slice.call(arguments, 1));
route[method].apply(route, slice.call(arguments, 1));
return this;
};
});
@@ -409,17 +490,18 @@ methods.forEach(function(method){
* @param {String} path
* @param {Function} ...
* @return {app} for chaining
* @api public
* @public
*/
app.all = function(path){
app.all = function all(path) {
this.lazyrouter();
var route = this._router.route(path);
var args = [].slice.call(arguments, 1);
methods.forEach(function(method){
route[method].apply(route, args);
});
var args = slice.call(arguments, 1);
for (var i = 0; i < methods.length; i++) {
route[methods[i]].apply(route, args);
}
return this;
};
@@ -440,63 +522,73 @@ app.del = deprecate.function(app.delete, 'app.del: Use app.delete instead');
* })
*
* @param {String} name
* @param {String|Function} options or fn
* @param {Function} fn
* @api public
* @param {Object|Function} options or fn
* @param {Function} callback
* @public
*/
app.render = function(name, options, fn){
var opts = {};
app.render = function render(name, options, callback) {
var cache = this.cache;
var done = callback;
var engines = this.engines;
var opts = options;
var renderOptions = {};
var view;
// support callback function as second arg
if ('function' == typeof options) {
fn = options, options = {};
if (typeof options === 'function') {
done = options;
opts = {};
}
// merge app.locals
mixin(opts, this.locals);
merge(renderOptions, this.locals);
// merge options._locals
if (options._locals) mixin(opts, options._locals);
if (opts._locals) {
merge(renderOptions, opts._locals);
}
// merge options
mixin(opts, options);
merge(renderOptions, opts);
// set .cache unless explicitly provided
opts.cache = null == opts.cache
? this.enabled('view cache')
: opts.cache;
if (renderOptions.cache == null) {
renderOptions.cache = this.enabled('view cache');
}
// primed cache
if (opts.cache) view = cache[name];
if (renderOptions.cache) {
view = cache[name];
}
// view
if (!view) {
view = new (this.get('view'))(name, {
var View = this.get('view');
view = new View(name, {
defaultEngine: this.get('view engine'),
root: this.get('views'),
engines: engines
});
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);
return done(err);
}
// prime the cache
if (opts.cache) cache[name] = view;
if (renderOptions.cache) {
cache[name] = view;
}
}
// render
try {
view.render(opts, fn);
} catch (err) {
fn(err);
}
tryRender(view, renderOptions, done);
};
/**
@@ -517,21 +609,35 @@ app.render = function(name, options, fn){
* https.createServer({ ... }, app).listen(443);
*
* @return {http.Server}
* @api public
* @public
*/
app.listen = function(){
app.listen = function listen() {
var server = http.createServer(this);
return server.listen.apply(server, arguments);
};
/**
* Log error using console.error.
*
* @param {Error} err
* @api public
*/
* Log error using console.error.
*
* @param {Error} err
* @private
*/
function logerror(err){
function logerror(err) {
/* istanbul ignore next */
if (this.get('env') !== 'test') console.error(err.stack || err.toString());
}
/**
* Try rendering a view.
* @private
*/
function tryRender(view, options, callback) {
try {
view.render(options, callback);
} catch (err) {
callback(err);
}
}

View File

@@ -1,9 +1,19 @@
/*!
* express
* Copyright(c) 2009-2013 TJ Holowaychuk
* Copyright(c) 2013 Roman Shtylman
* Copyright(c) 2014-2015 Douglas Christopher Wilson
* MIT Licensed
*/
'use strict';
/**
* Module dependencies.
*/
var EventEmitter = require('events').EventEmitter;
var mixin = require('utils-merge');
var mixin = require('merge-descriptors');
var proto = require('./application');
var Route = require('./router/route');
var Router = require('./router');
@@ -28,8 +38,8 @@ function createApplication() {
app.handle(req, res, next);
};
mixin(app, proto);
mixin(app, EventEmitter.prototype);
mixin(app, EventEmitter.prototype, false);
mixin(app, proto, false);
app.request = { __proto__: req, app: app };
app.response = { __proto__: res, app: app };

View File

@@ -1,6 +1,16 @@
/*!
* express
* Copyright(c) 2009-2013 TJ Holowaychuk
* Copyright(c) 2013 Roman Shtylman
* Copyright(c) 2014-2015 Douglas Christopher Wilson
* MIT Licensed
*/
'use strict';
/**
* Initialization middleware, exposing the
* request and response to eachother, as well
* request and response to each other, as well
* as defaulting the X-Powered-By header field.
*
* @param {Function} app

View File

@@ -1,37 +1,44 @@
/*!
* express
* Copyright(c) 2009-2013 TJ Holowaychuk
* Copyright(c) 2013 Roman Shtylman
* Copyright(c) 2014-2015 Douglas Christopher Wilson
* MIT Licensed
*/
'use strict';
/**
* Module dependencies.
*/
var qs = require('qs');
var parseUrl = require('parseurl');
var qs = require('qs');
/**
* Query:
*
* Automatically parse the query-string when available,
* populating the `req.query` object using
* [qs](https://github.com/visionmedia/node-querystring).
*
* Examples:
*
* .use(connect.query())
* .use(function(req, res){
* res.end(JSON.stringify(req.query));
* });
*
* The `options` passed are provided to qs.parse function.
*
* @param {Object} options
* @return {Function}
* @api public
*/
module.exports = function query(options){
module.exports = function query(options) {
var opts = Object.create(options || null);
var queryparse = qs.parse;
if (typeof options === 'function') {
queryparse = options;
opts = undefined;
}
if (opts !== undefined && opts.allowPrototypes === undefined) {
// back-compat for qs module
opts.allowPrototypes = true;
}
return function query(req, res, next){
if (!req.query) {
req.query = ~req.url.indexOf('?')
? qs.parse(parseUrl(req).query, options)
: {};
var val = parseUrl(req).query;
req.query = queryparse(val, opts);
}
next();

View File

@@ -1,9 +1,21 @@
/*!
* express
* Copyright(c) 2009-2013 TJ Holowaychuk
* Copyright(c) 2013 Roman Shtylman
* Copyright(c) 2014-2015 Douglas Christopher Wilson
* MIT Licensed
*/
'use strict';
/**
* Module dependencies.
* @private
*/
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');
@@ -40,18 +52,28 @@ var req = exports = module.exports = {
*
* @param {String} name
* @return {String}
* @api public
* @public
*/
req.get =
req.header = function(name){
switch (name = name.toLowerCase()) {
req.header = function header(name) {
if (!name) {
throw new TypeError('name argument is required to req.get');
}
if (typeof name !== 'string') {
throw new TypeError('name must be a string to req.get');
}
var lc = name.toLowerCase();
switch (lc) {
case 'referer':
case 'referrer':
return this.headers.referrer
|| this.headers.referer;
default:
return this.headers[name];
return this.headers[lc];
}
};
@@ -62,12 +84,12 @@ req.header = function(name){
* the best match when true, otherwise `undefined`, in which
* case you should respond with 406 "Not Acceptable".
*
* The `type` value may be a single mime type string
* such as "application/json", the extension name
* such as "json", a comma-delimted list such as "json, html, text/plain",
* The `type` value may be a single MIME type string
* such as "application/json", an extension name
* such as "json", a comma-delimited list such as "json, html, text/plain",
* an argument list such as `"json", "html", "text/plain"`,
* or an array `["json", "html", "text/plain"]`. When a list
* or array is given the _best_ match, if any is returned.
* or array is given, the _best_ match, if any is returned.
*
* Examples:
*
@@ -97,8 +119,8 @@ req.header = function(name){
* // => "json"
*
* @param {String|Array} type(s)
* @return {String}
* @api public
* @return {String|Array|Boolean}
* @public
*/
req.accepts = function(){
@@ -110,8 +132,8 @@ req.accepts = function(){
* Check if the given `encoding`s are accepted.
*
* @param {String} ...encoding
* @return {Boolean}
* @api public
* @return {String|Array}
* @public
*/
req.acceptsEncodings = function(){
@@ -127,8 +149,8 @@ req.acceptsEncoding = deprecate.function(req.acceptsEncodings,
* otherwise you should respond with 406 "Not Acceptable".
*
* @param {String} ...charset
* @return {Boolean}
* @api public
* @return {String|Array}
* @public
*/
req.acceptsCharsets = function(){
@@ -144,8 +166,8 @@ req.acceptsCharset = deprecate.function(req.acceptsCharsets,
* otherwise you should respond with 406 "Not Acceptable".
*
* @param {String} ...lang
* @return {Boolean}
* @api public
* @return {String|Array}
* @public
*/
req.acceptsLanguages = function(){
@@ -157,29 +179,34 @@ req.acceptsLanguage = deprecate.function(req.acceptsLanguages,
'req.acceptsLanguage: Use acceptsLanguages instead');
/**
* Parse Range header field,
* capping to the given `size`.
* Parse Range header field, capping to the given `size`.
*
* Unspecified ranges such as "0-" require
* knowledge of your resource length. In
* the case of a byte range this is of course
* the total number of bytes. If the Range
* header field is not given `null` is returned,
* `-1` when unsatisfiable, `-2` when syntactically invalid.
* Unspecified ranges such as "0-" require knowledge of your resource length. In
* the case of a byte range this is of course the total number of bytes. If the
* Range header field is not given `undefined` is returned, `-1` when unsatisfiable,
* and `-2` when syntactically invalid.
*
* NOTE: remember that ranges are inclusive, so
* for example "Range: users=0-3" should respond
* with 4 users when available, not 3.
* When ranges are returned, the array has a "type" property which is the type of
* range that is required (most commonly, "bytes"). Each array element is an object
* with a "start" and "end" property for the portion of the range.
*
* @param {Number} size
* @return {Array}
* @api public
* The "combine" option can be set to `true` and overlapping & adjacent ranges
* will be combined into a single range.
*
* NOTE: remember that ranges are inclusive, so for example "Range: users=0-3"
* should respond with 4 users when available, not 3.
*
* @param {number} size
* @param {object} [options]
* @param {boolean} [options.combine=false]
* @return {number|array}
* @public
*/
req.range = function(size){
req.range = function range(size, options) {
var range = this.get('Range');
if (!range) return;
return parseRange(size, range);
return parseRange(size, range, options);
};
/**
@@ -196,16 +223,23 @@ req.range = function(size){
* @param {String} name
* @param {Mixed} [defaultValue]
* @return {String}
* @api public
* @public
*/
req.param = function(name, defaultValue){
req.param = function param(name, defaultValue) {
var params = this.params || {};
var body = this.body || {};
var query = this.query || {};
var args = arguments.length === 1
? 'name'
: 'name, default';
deprecate('req.param(' + args + '): Use req.params, req.body, or req.query instead');
if (null != params[name] && params.hasOwnProperty(name)) return params[name];
if (null != body[name]) return body[name];
if (null != query[name]) return query[name];
return defaultValue;
};
@@ -230,54 +264,66 @@ req.param = function(name, defaultValue){
* req.is('html');
* // => false
*
* @param {String} type
* @return {Boolean}
* @api public
* @param {String|Array} types...
* @return {String|false|null}
* @public
*/
req.is = function(types){
if (!Array.isArray(types)) types = [].slice.call(arguments);
return typeis(this, types);
req.is = function is(types) {
var arr = types;
// support flattened arguments
if (!Array.isArray(types)) {
arr = new Array(arguments.length);
for (var i = 0; i < arr.length; i++) {
arr[i] = arguments[i];
}
}
return typeis(this, arr);
};
/**
* Return the protocol string "http" or "https"
* when requested with TLS. When the "trust proxy"
* setting trusts the socket address, the
* "X-Forwarded-Proto" header field will be trusted.
* "X-Forwarded-Proto" header field will be trusted
* and used if present.
*
* If you're running behind a reverse proxy that
* supplies https for you this may be enabled.
*
* @return {String}
* @api public
* @public
*/
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 this.connection.encrypted
? 'https'
: 'http';
if (!trust(this.connection.remoteAddress, 0)) {
return proto;
}
// Note: X-Forwarded-Proto is normally only ever a
// single value, but this is to be safe.
var proto = this.get('X-Forwarded-Proto') || 'http';
proto = this.get('X-Forwarded-Proto') || proto;
return proto.split(/\s*,\s*/)[0];
});
/**
* Short-hand for:
*
* req.protocol == 'https'
* req.protocol === 'https'
*
* @return {Boolean}
* @api public
* @public
*/
defineGetter(req, 'secure', function secure(){
return 'https' == this.protocol;
return this.protocol === 'https';
});
/**
@@ -287,7 +333,7 @@ defineGetter(req, 'secure', function secure(){
* "trust proxy" is set.
*
* @return {String}
* @api public
* @public
*/
defineGetter(req, 'ip', function ip(){
@@ -304,7 +350,7 @@ defineGetter(req, 'ip', function ip(){
* "proxy2" were trusted.
*
* @return {Array}
* @api public
* @public
*/
defineGetter(req, 'ips', function ips() {
@@ -325,22 +371,27 @@ defineGetter(req, 'ips', function ips() {
* If "subdomain offset" is 3, req.subdomains is `["tobi"]`.
*
* @return {Array}
* @api public
* @public
*/
defineGetter(req, 'subdomains', function subdomains() {
var hostname = this.hostname;
if (!hostname) return [];
var offset = this.app.get('subdomain offset');
return (this.hostname || '')
.split('.')
.reverse()
.slice(offset);
var subdomains = !isIP(hostname)
? hostname.split('.').reverse()
: [hostname];
return subdomains.slice(offset);
});
/**
* Short-hand for `url.parse(req.url).pathname`.
*
* @return {String}
* @api public
* @public
*/
defineGetter(req, 'path', function path() {
@@ -355,14 +406,14 @@ defineGetter(req, 'path', function path() {
* be trusted.
*
* @return {String}
* @api public
* @public
*/
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)) {
if (!host || !trust(this.connection.remoteAddress, 0)) {
host = this.get('Host');
}
@@ -374,7 +425,7 @@ defineGetter(req, 'hostname', function hostname(){
: 0;
var index = host.indexOf(':', offset);
return ~index
return index !== -1
? host.substring(0, index)
: host;
});
@@ -391,7 +442,7 @@ defineGetter(req, 'host', deprecate.function(function host(){
* still match.
*
* @return {Boolean}
* @api public
* @public
*/
defineGetter(req, 'fresh', function(){
@@ -399,11 +450,11 @@ defineGetter(req, 'fresh', function(){
var s = this.res.statusCode;
// GET or HEAD for weak freshness validation only
if ('GET' != method && 'HEAD' != method) return false;
if ('GET' !== method && 'HEAD' !== method) return false;
// 2xx or 304 as per rfc2616 14.26
if ((s >= 200 && s < 300) || 304 == s) {
return fresh(this.headers, this.res._headers);
if ((s >= 200 && s < 300) || 304 === s) {
return fresh(this.headers, (this.res._headers || {}));
}
return false;
@@ -415,7 +466,7 @@ defineGetter(req, 'fresh', function(){
* resource has changed.
*
* @return {Boolean}
* @api public
* @public
*/
defineGetter(req, 'stale', function stale(){
@@ -426,12 +477,12 @@ defineGetter(req, 'stale', function stale(){
* Check if the request was an _XMLHttpRequest_.
*
* @return {Boolean}
* @api public
* @public
*/
defineGetter(req, 'xhr', function xhr(){
var val = this.get('X-Requested-With') || '';
return 'xmlhttprequest' == val.toLowerCase();
return val.toLowerCase() === 'xmlhttprequest';
});
/**
@@ -440,7 +491,7 @@ defineGetter(req, 'xhr', function xhr(){
* @param {Object} obj
* @param {String} name
* @param {Function} getter
* @api private
* @private
*/
function defineGetter(obj, name, getter) {
Object.defineProperty(obj, name, {

File diff suppressed because it is too large Load Diff

View File

@@ -1,5 +1,16 @@
/*!
* express
* Copyright(c) 2009-2013 TJ Holowaychuk
* Copyright(c) 2013 Roman Shtylman
* Copyright(c) 2014-2015 Douglas Christopher Wilson
* MIT Licensed
*/
'use strict';
/**
* Module dependencies.
* @private
*/
var Route = require('./route');
@@ -7,19 +18,29 @@ var Layer = require('./layer');
var methods = require('methods');
var mixin = require('utils-merge');
var debug = require('debug')('express:router');
var deprecate = require('depd')('express');
var flatten = require('array-flatten');
var parseUrl = require('parseurl');
/**
* Module variables.
* @private
*/
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
* @return {Router} which is an callable function
* @api public
* @public
*/
var proto = module.exports = function(options) {
options = options || {};
var opts = options || {};
function router(req, res, next) {
router.handle(req, res, next);
@@ -30,9 +51,9 @@ var proto = module.exports = function(options) {
router.params = {};
router._params = [];
router.caseSensitive = options.caseSensitive;
router.mergeParams = options.mergeParams;
router.strict = options.strict;
router.caseSensitive = opts.caseSensitive;
router.mergeParams = opts.mergeParams;
router.strict = opts.strict;
router.stack = [];
return router;
@@ -69,12 +90,13 @@ var proto = module.exports = function(options) {
* @param {String} name
* @param {Function} fn
* @return {app} for chaining
* @api public
* @public
*/
proto.param = function(name, fn){
proto.param = function param(name, fn) {
// param logic
if ('function' == typeof name) {
if (typeof name === 'function') {
deprecate('router.param(fn): Refactor to use path params');
this._params.push(name);
return;
}
@@ -85,6 +107,7 @@ proto.param = function(name, fn){
var ret;
if (name[0] === ':') {
deprecate('router.param(' + JSON.stringify(name) + ', fn): Use router.param(' + JSON.stringify(name.substr(1)) + ', fn) instead');
name = name.substr(1);
}
@@ -96,7 +119,7 @@ proto.param = function(name, fn){
// ensure we end up with a
// middleware function
if ('function' != typeof fn) {
if ('function' !== typeof fn) {
throw new Error('invalid param() call for ' + name + ', got ' + fn);
}
@@ -106,20 +129,17 @@ proto.param = function(name, fn){
/**
* Dispatch a req, res into the router.
*
* @api private
* @private
*/
proto.handle = function(req, res, done) {
proto.handle = function handle(req, res, out) {
var self = this;
debug('dispatching %s %s', req.method, req.url);
var method = req.method.toLowerCase();
var search = 1 + req.url.indexOf('?');
var pathlength = search ? search - 1 : req.url.length;
var fqdn = 1 + req.url.substr(0, pathlength).indexOf('://');
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 = '';
@@ -136,112 +156,142 @@ proto.handle = function(req, res, done) {
// manage inter-router variables
var parentParams = req.params;
var parentUrl = req.baseUrl || '';
done = restore(done, req, 'baseUrl', 'next', 'params');
var done = restore(out, req, 'baseUrl', 'next', 'params');
// setup next layer
req.next = next;
// for options requests, respond with a default if nothing else responds
if (method === 'options') {
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);
sendOptionsResponse(res, options, old);
});
}
// setup basic req values
req.baseUrl = parentUrl;
req.originalUrl = req.originalUrl || req.url;
next();
function next(err) {
if (err === 'route') {
err = undefined;
}
var layer = stack[idx++];
var layerPath;
if (!layer) {
return done(err);
}
var layerError = err === 'route'
? null
: err;
// remove added slash
if (slashAdded) {
req.url = req.url.substr(1);
slashAdded = false;
}
req.baseUrl = parentUrl;
req.url = protohost + removed + req.url.substr(protohost.length);
req.originalUrl = req.originalUrl || req.url;
removed = '';
try {
var path = parseUrl(req).pathname;
if (undefined == path) path = '/';
if (!layer.match(path)) return next(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 (err) {
return next(err);
}
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;
layerPath = layer.path;
// this should be done for the layer
return self.process_params(layer, paramcalled, req, res, function(err) {
if (err) {
return next(err);
}
if (route) {
return layer.handle(req, res, next);
}
trim_prefix();
});
} catch (err) {
next(err);
// restore altered req.url
if (removed.length !== 0) {
req.baseUrl = parentUrl;
req.url = protohost + removed + req.url.substr(protohost.length);
removed = '';
}
function trim_prefix() {
var c = path[layerPath.length];
if (c && '/' != c && '.' != c) return next(err);
// no more matching layers
if (idx >= stack.length) {
setImmediate(done, layerError);
return;
}
// Trim off the part of the url that matches the route
// middleware (.use stuff) needs to have the path stripped
removed = layerPath;
if (removed.length) {
debug('trim prefix (%s) from url %s', layerPath, req.url);
req.url = protohost + req.url.substr(protohost.length + removed.length);
// get pathname of request
var path = getPathname(req);
if (path == null) {
return done(layerError);
}
// find next matching layer
var layer;
var match;
var route;
while (match !== true && idx < stack.length) {
layer = stack[idx++];
match = matchLayer(layer, path);
route = layer.route;
if (typeof match !== 'boolean') {
// hold on to layerError
layerError = layerError || match;
}
if (match !== true) {
continue;
}
if (!route) {
// process non-route handlers normally
continue;
}
if (layerError) {
// routes do not match with a pending error
match = false;
continue;
}
var method = req.method;
var has_method = route._handles_method(method);
// build up automatic options response
if (!has_method && method === 'OPTIONS') {
appendMethods(options, route._options());
}
// don't even bother matching route
if (!has_method && method !== 'HEAD') {
match = false;
continue;
}
}
// no match
if (match !== true) {
return done(layerError);
}
// store route for dispatch on change
if (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;
@@ -249,36 +299,27 @@ proto.handle = function(req, res, done) {
}
// Setup base URL (no trailing slash)
if (removed.length && removed.substr(-1) === '/') {
req.baseUrl = parentUrl + removed.substring(0, removed.length - 1);
} else {
req.baseUrl = parentUrl + removed;
}
req.baseUrl = parentUrl + (removed[removed.length - 1] === '/'
? removed.substring(0, removed.length - 1)
: removed);
}
debug('%s %s : %s', layer.handle.name || 'anonymous', layerPath, req.originalUrl);
var arity = layer.handle.length;
try {
if (err && arity === 4) {
layer.handle(err, req, res, next);
} else if (!err && arity < 4) {
layer.handle(req, res, next);
} else {
next(err);
}
} catch (err) {
next(err);
}
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);
}
}
};
/**
* Process any parameters for the layer.
*
* @api private
* @private
*/
proto.process_params = function(layer, called, req, res, done) {
proto.process_params = function process_params(layer, called, req, res, done) {
var params = this.params;
// captured parameters from the layer, keys and values
@@ -325,7 +366,8 @@ proto.process_params = function(layer, called, req, res, done) {
}
// param previously called with same value or error occurred
if (paramCalled && (paramCalled.error || paramCalled.match === paramVal)) {
if (paramCalled && (paramCalled.match === paramVal
|| (paramCalled.error && paramCalled.error !== 'route'))) {
// restore value
req.params[name] = paramCalled.value;
@@ -339,11 +381,7 @@ proto.process_params = function(layer, called, req, res, done) {
value: paramVal
};
try {
return paramCallback();
} catch (err) {
return done(err);
}
paramCallback();
}
// single param callbacks
@@ -362,7 +400,11 @@ proto.process_params = function(layer, called, req, res, done) {
if (!fn) return param();
fn(req, res, paramCallback, paramVal, key.name);
try {
fn(req, res, paramCallback, paramVal, key.name);
} catch (e) {
paramCallback(e);
}
}
param();
@@ -380,40 +422,56 @@ proto.process_params = function(layer, called, req, res, done) {
* handlers can operate without any code changes regardless of the "prefix"
* pathname.
*
* @param {String|Function} route
* @param {Function} fn
* @return {app} for chaining
* @api public
* @public
*/
proto.use = function(route, fn){
// default route to '/'
if ('string' != typeof route) {
fn = route;
route = '/';
}
proto.use = function use(fn) {
var offset = 0;
var path = '/';
// default path to '/'
// disambiguate router.use([fn])
if (typeof fn !== 'function') {
var type = {}.toString.call(fn);
var msg = 'Router.use() requires callback functions but got a ' + type;
throw new Error(msg);
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;
}
}
// strip trailing slash
if ('/' == route[route.length - 1]) {
route = route.slice(0, -1);
var callbacks = flatten(slice.call(arguments, offset));
if (callbacks.length === 0) {
throw new TypeError('Router.use() requires middleware functions');
}
var layer = new Layer(route, {
sensitive: this.caseSensitive,
strict: this.strict,
end: false
}, fn);
for (var i = 0; i < callbacks.length; i++) {
var fn = callbacks[i];
// add the middleware
debug('use %s %s', route || '/', fn.name || 'anonymous');
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.stack.push(layer);
return this;
};
@@ -427,10 +485,10 @@ proto.use = function(route, fn){
*
* @param {String} path
* @return {Route}
* @api public
* @public
*/
proto.route = function(path){
proto.route = function route(path) {
var route = new Route(path);
var layer = new Layer(path, {
@@ -449,11 +507,59 @@ proto.route = function(path){
methods.concat('all').forEach(function(method){
proto[method] = function(path){
var route = this.route(path)
route[method].apply(route, [].slice.call(arguments, 1));
route[method].apply(route, slice.call(arguments, 1));
return this;
};
});
// append methods to a list of methods
function appendMethods(list, addition) {
for (var i = 0; i < addition.length; i++) {
var method = addition[i];
if (list.indexOf(method) === -1) {
list.push(method);
}
}
}
// get pathname of request
function getPathname(req) {
try {
return parseUrl(req).pathname;
} catch (err) {
return undefined;
}
}
// 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');
}
/**
* Match path to a layer.
*
* @param {Layer} layer
* @param {string} path
* @private
*/
function matchLayer(layer, path) {
try {
return layer.match(path);
} catch (err) {
return err;
}
}
// merge params with parent params
function mergeParams(params, parent) {
if (typeof parent !== 'object' || !parent) {
@@ -472,9 +578,12 @@ function mergeParams(params, parent) {
var o = 0;
// determine numeric gaps
while (i === o || o in parent) {
if (i in params) i++;
if (o in parent) o++;
while (i in params) {
i++;
}
while (o in parent) {
o++;
}
// offset numeric indices in params before merge
@@ -487,7 +596,7 @@ function mergeParams(params, parent) {
}
}
return mixin(parent, params);
return mixin(obj, params);
}
// restore obj props after function
@@ -510,10 +619,27 @@ function restore(fn, obj) {
};
}
// send an OPTIONS response
function sendOptionsResponse(res, options, next) {
try {
var body = options.join(',');
res.set('Allow', body);
res.send(body);
} catch (err) {
next(err);
}
}
// wrap a function
function wrap(old, fn) {
return function () {
var args = [old].concat(slice.call(arguments));
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);
};
}

View File

@@ -1,12 +1,31 @@
/*!
* express
* Copyright(c) 2009-2013 TJ Holowaychuk
* Copyright(c) 2013 Roman Shtylman
* Copyright(c) 2014-2015 Douglas Christopher Wilson
* MIT Licensed
*/
'use strict';
/**
* Module dependencies.
* @private
*/
var pathRegexp = require('path-to-regexp');
var debug = require('debug')('express:router:layer');
/**
* Expose `Layer`.
* Module variables.
* @private
*/
var hasOwnProperty = Object.prototype.hasOwnProperty;
/**
* Module exports.
* @public
*/
module.exports = Layer;
@@ -17,11 +36,68 @@ function Layer(path, options, fn) {
}
debug('new %s', path);
options = options || {};
this.regexp = pathRegexp(path, this.keys = [], options);
var opts = options || {};
this.handle = fn;
this.name = fn.name || '<anonymous>';
this.params = undefined;
this.path = undefined;
this.regexp = pathRegexp(path, this.keys = [], opts);
if (path === '/' && opts.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`.
@@ -31,26 +107,43 @@ function Layer(path, options, fn) {
* @api private
*/
Layer.prototype.match = function(path){
var keys = this.keys;
var params = this.params = {};
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);
var n = 0;
var key;
var val;
if (!m) return false;
if (!m) {
this.params = undefined;
this.path = undefined;
return false;
}
// store values
this.params = {};
this.path = m[0];
for (var i = 1, len = m.length; i < len; ++i) {
key = keys[i - 1];
val = decode_param(m[i]);
var keys = this.keys;
var params = this.params;
if (key) {
params[key.name] = val;
} else {
params[n++] = val;
for (var i = 1; i < m.length; i++) {
var key = keys[i - 1];
var prop = key.name;
var val = decode_param(m[i]);
if (val !== undefined || !(hasOwnProperty.call(params, prop))) {
params[prop] = val;
}
}
@@ -62,19 +155,22 @@ Layer.prototype.match = function(path){
*
* @param {string} val
* @return {string}
* @api private
* @private
*/
function decode_param(val){
if (typeof val !== 'string') {
function decode_param(val) {
if (typeof val !== 'string' || val.length === 0) {
return val;
}
try {
return decodeURIComponent(val);
} catch (e) {
var err = new TypeError("Failed to decode param '" + val + "'");
err.status = 400;
} catch (err) {
if (err instanceof URIError) {
err.message = 'Failed to decode param \'' + val + '\'';
err.status = err.statusCode = 400;
}
throw err;
}
}

View File

@@ -1,13 +1,34 @@
/*!
* express
* Copyright(c) 2009-2013 TJ Holowaychuk
* Copyright(c) 2013 Roman Shtylman
* Copyright(c) 2014-2015 Douglas Christopher Wilson
* MIT Licensed
*/
'use strict';
/**
* Module dependencies.
* @private
*/
var debug = require('debug')('express:router:route');
var flatten = require('array-flatten');
var Layer = require('./layer');
var methods = require('methods');
var utils = require('../utils');
/**
* Expose `Route`.
* Module variables.
* @private
*/
var slice = Array.prototype.slice;
var toString = Object.prototype.toString;
/**
* Module exports.
* @public
*/
module.exports = Route;
@@ -16,20 +37,22 @@ module.exports = Route;
* Initialize `Route` with the given `path`,
*
* @param {String} path
* @api private
* @public
*/
function Route(path) {
debug('new %s', path);
this.path = path;
this.stack = [];
debug('new %s', path);
// route handlers for various http methods
this.methods = {};
}
/**
* @api private
* Determine if the route handles a given method.
* @private
*/
Route.prototype._handles_method = function _handles_method(method) {
@@ -37,33 +60,43 @@ Route.prototype._handles_method = function _handles_method(method) {
return true;
}
method = method.toLowerCase();
var name = method.toLowerCase();
if (method === 'head' && !this.methods['head']) {
method = 'get';
if (name === 'head' && !this.methods['head']) {
name = 'get';
}
return Boolean(this.methods[method]);
return Boolean(this.methods[name]);
};
/**
* @return {Array} supported HTTP methods
* @api private
* @private
*/
Route.prototype._options = function(){
return Object.keys(this.methods).map(function(method) {
return method.toUpperCase();
});
Route.prototype._options = function _options() {
var methods = Object.keys(this.methods);
// append automatic head
if (this.methods.get && !this.methods.head) {
methods.push('head');
}
for (var i = 0; i < methods.length; i++) {
// make upper case
methods[i] = methods[i].toUpperCase();
}
return methods;
};
/**
* dispatch req, res into this route
*
* @api private
* @private
*/
Route.prototype.dispatch = function(req, res, done){
Route.prototype.dispatch = function dispatch(req, res, done) {
var idx = 0;
var stack = this.stack;
if (stack.length === 0) {
return done();
@@ -76,8 +109,9 @@ Route.prototype.dispatch = function(req, res, done){
req.route = this;
var idx = 0;
(function next_layer(err) {
next();
function next(err) {
if (err && err === 'route') {
return done();
}
@@ -88,33 +122,15 @@ Route.prototype.dispatch = function(req, res, done){
}
if (layer.method && layer.method !== method) {
return next_layer(err);
return next(err);
}
var arity = layer.handle.length;
if (err) {
if (arity < 4) {
return next_layer(err);
}
try {
layer.handle(err, req, res, next_layer);
} catch (err) {
next_layer(err);
}
return;
layer.handle_error(err, req, res, next);
} else {
layer.handle_request(req, res, next);
}
if (arity > 3) {
return next_layer();
}
try {
layer.handle(req, res, next_layer);
} catch (err) {
next_layer(err);
}
})();
}
};
/**
@@ -145,43 +161,50 @@ Route.prototype.dispatch = function(req, res, done){
* @api public
*/
Route.prototype.all = function(){
var self = this;
var callbacks = utils.flatten([].slice.call(arguments));
callbacks.forEach(function(fn) {
if (typeof fn !== 'function') {
var type = {}.toString.call(fn);
Route.prototype.all = function all() {
var handles = flatten(slice.call(arguments));
for (var i = 0; i < handles.length; i++) {
var handle = handles[i];
if (typeof handle !== 'function') {
var type = toString.call(handle);
var msg = 'Route.all() requires callback functions but got a ' + type;
throw new Error(msg);
throw new TypeError(msg);
}
self.methods._all = true;
self.stack.push({ handle: fn });
});
var layer = Layer('/', {}, handle);
layer.method = undefined;
return self;
this.methods._all = true;
this.stack.push(layer);
}
return this;
};
methods.forEach(function(method){
Route.prototype[method] = function(){
var self = this;
var callbacks = utils.flatten([].slice.call(arguments));
var handles = flatten(slice.call(arguments));
callbacks.forEach(function(fn) {
if (typeof fn !== 'function') {
var type = {}.toString.call(fn);
for (var i = 0; i < handles.length; i++) {
var handle = handles[i];
if (typeof handle !== 'function') {
var type = toString.call(handle);
var msg = 'Route.' + method + '() requires callback functions but got a ' + type;
throw new Error(msg);
}
debug('%s %s', method, self.path);
debug('%s %s', method, this.path);
if (!self.methods[method]) {
self.methods[method] = true;
}
var layer = Layer('/', {}, handle);
layer.method = method;
self.stack.push({ method: method, handle: fn });
});
return self;
this.methods[method] = true;
this.stack.push(layer);
}
return this;
};
});

View File

@@ -1,13 +1,27 @@
/**
* Module dependencies.
/*!
* express
* Copyright(c) 2009-2013 TJ Holowaychuk
* Copyright(c) 2014-2015 Douglas Christopher Wilson
* MIT Licensed
*/
'use strict';
/**
* Module dependencies.
* @api private
*/
var contentDisposition = require('content-disposition');
var contentType = require('content-type');
var deprecate = require('depd')('express');
var flatten = require('array-flatten');
var mime = require('send').mime;
var crc32 = require('buffer-crc32');
var crypto = require('crypto');
var basename = require('path').basename;
var etag = require('etag');
var proxyaddr = require('proxy-addr');
var typer = require('media-typer');
var qs = require('qs');
var querystring = require('querystring');
/**
* Return strong ETag for `body`.
@@ -18,17 +32,12 @@ var typer = require('media-typer');
* @api private
*/
exports.etag = function etag(body, encoding){
if (body.length === 0) {
// fast-path empty body
return '"1B2M2Y8AsgTpgAmY7PhCfg=="'
}
exports.etag = function (body, encoding) {
var buf = !Buffer.isBuffer(body)
? new Buffer(body, encoding)
: body;
var hash = crypto
.createHash('md5')
.update(body, encoding)
.digest('base64')
return '"' + hash + '"'
return etag(buf, {weak: false});
};
/**
@@ -41,16 +50,11 @@ exports.etag = function etag(body, encoding){
*/
exports.wetag = function wetag(body, encoding){
if (body.length === 0) {
// fast-path empty body
return 'W/"0-0"'
}
var buf = !Buffer.isBuffer(body)
? new Buffer(body, encoding)
: body;
var buf = Buffer.isBuffer(body)
? body
: new Buffer(body, encoding)
var len = buf.length
return 'W/"' + len.toString(16) + '-' + crc32.unsigned(buf) + '"'
return etag(buf, {weak: true});
};
/**
@@ -62,9 +66,9 @@ exports.wetag = function wetag(body, encoding){
*/
exports.isAbsolute = function(path){
if ('/' == path[0]) return true;
if (':' == path[1] && '\\' == path[2]) return true;
if ('\\\\' == path.substring(0, 2)) return true; // Microsoft Azure absolute path
if ('/' === path[0]) return true;
if (':' === path[1] && ('\\' === path[2] || '/' === path[2])) return true; // Windows device path
if ('\\\\' === path.substring(0, 2)) return true; // Microsoft Azure absolute path
};
/**
@@ -75,18 +79,8 @@ exports.isAbsolute = function(path){
* @api private
*/
exports.flatten = function(arr, ret){
ret = ret || [];
var len = arr.length;
for (var i = 0; i < len; ++i) {
if (Array.isArray(arr[i])) {
exports.flatten(arr[i], ret);
} else {
ret.push(arr[i]);
}
}
return ret;
};
exports.flatten = deprecate.function(flatten,
'utils.flatten: use array-flatten npm module instead');
/**
* Normalize the given `type`, for example "html" becomes "text/html".
@@ -129,18 +123,8 @@ exports.normalizeTypes = function(types){
* @api private
*/
exports.contentDisposition = function(filename){
var ret = 'attachment';
if (filename) {
filename = basename(filename);
// if filename contains non-ascii characters, add a utf-8 version ala RFC 5987
ret = /[^\040-\176]/.test(filename)
? 'attachment; filename="' + encodeURI(filename) + '"; filename*=UTF-8\'\'' + encodeURI(filename)
: 'attachment; filename="' + filename + '"';
}
return ret;
};
exports.contentDisposition = deprecate.function(contentDisposition,
'utils.contentDisposition: use content-disposition npm module instead');
/**
* Parse accept params `str` returning an
@@ -158,7 +142,7 @@ function acceptParams(str, index) {
for (var i = 1; i < parts.length; ++i) {
var pms = parts[i].split(/ *= */);
if ('q' == pms[0]) {
if ('q' === pms[0]) {
ret.quality = parseFloat(pms[1]);
} else {
ret.params[pms[0]] = pms[1];
@@ -202,6 +186,41 @@ exports.compileETag = 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 = parseExtendedQueryString;
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.
*
@@ -240,15 +259,41 @@ exports.compileTrust = function(val) {
* @api private
*/
exports.setCharset = function(type, charset){
if (!type || !charset) return type;
exports.setCharset = function setCharset(type, charset) {
if (!type || !charset) {
return type;
}
// parse type
var parsed = typer.parse(type);
var parsed = contentType.parse(type);
// set charset
parsed.parameters.charset = charset;
// format type
return typer.format(parsed);
return contentType.format(parsed);
};
/**
* Parse an extended query string with qs.
*
* @return {Object}
* @private
*/
function parseExtendedQueryString(str) {
return qs.parse(str, {
allowPrototypes: true
});
}
/**
* Return new empty object.
*
* @return {Object}
* @api private
*/
function newObject() {
return {};
}

View File

@@ -1,18 +1,37 @@
/**
* Module dependencies.
/*!
* express
* Copyright(c) 2009-2013 TJ Holowaychuk
* Copyright(c) 2013 Roman Shtylman
* Copyright(c) 2014-2015 Douglas Christopher Wilson
* MIT Licensed
*/
'use strict';
/**
* Module dependencies.
* @private
*/
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 exists = fs.existsSync || path.existsSync;
var join = path.join;
var resolve = path.resolve;
/**
* Expose `View`.
* Module exports.
* @public
*/
module.exports = View;
@@ -26,52 +45,129 @@ module.exports = View;
* - `engines` template engine require() cache
* - `root` root path for view lookup
*
* @param {String} name
* @param {Object} options
* @api private
* @param {string} name
* @param {object} options
* @public
*/
function View(name, options) {
options = options || {};
var opts = options || {};
this.defaultEngine = opts.defaultEngine;
this.ext = extname(name);
this.name = name;
this.root = options.root;
var engines = options.engines;
this.defaultEngine = options.defaultEngine;
var ext = this.ext = extname(name);
if (!ext && !this.defaultEngine) throw new Error('No default engine was specified and no extension was provided.');
if (!ext) name += (ext = this.ext = ('.' != this.defaultEngine[0] ? '.' : '') + this.defaultEngine);
this.engine = engines[ext] || (engines[ext] = require(ext.slice(1)).__express);
this.path = this.lookup(name);
this.root = opts.root;
if (!this.ext && !this.defaultEngine) {
throw new Error('No default engine was specified and no extension was provided.');
}
var fileName = name;
if (!this.ext) {
// get extension from default engine name
this.ext = this.defaultEngine[0] !== '.'
? '.' + this.defaultEngine
: this.defaultEngine;
fileName += this.ext;
}
if (!opts.engines[this.ext]) {
// load engine
opts.engines[this.ext] = require(this.ext.substr(1)).__express;
}
// store loaded engine
this.engine = opts.engines[this.ext];
// lookup path
this.path = this.lookup(fileName);
}
/**
* Lookup view by the given `path`
* Lookup view by the given `name`
*
* @param {String} path
* @return {String}
* @api private
* @param {string} name
* @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;
};
/**
* Render with the given `options` and callback `fn(err, str)`.
* Render with the given options.
*
* @param {Object} options
* @param {Function} fn
* @api private
* @param {object} options
* @param {function} callback
* @private
*/
View.prototype.render = function(options, fn){
this.engine(this.path, options, fn);
View.prototype.render = function render(options, callback) {
debug('render "%s"', this.path);
this.engine(this.path, options, callback);
};
/**
* 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;
// <path>.<ext>
var path = join(dir, file);
var 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,7 +1,7 @@
{
"name": "express",
"description": "Fast, unopinionated, minimalist web framework",
"version": "4.5.0",
"version": "4.14.1",
"author": "TJ Holowaychuk <tj@vision-media.ca>",
"contributors": [
"Aaron Heckmann <aaron.heckmann+github@gmail.com>",
@@ -9,8 +9,12 @@
"Douglas Christopher Wilson <doug@somethingdoug.com>",
"Guillermo Rauch <rauchg@gmail.com>",
"Jonathan Ong <me@jongleberry.com>",
"Roman Shtylman <shtylman+expressjs@gmail.com"
"Roman Shtylman <shtylman+expressjs@gmail.com>",
"Young Jae Sim <hanul@hanul.me>"
],
"license": "MIT",
"repository": "expressjs/express",
"homepage": "http://expressjs.com/",
"keywords": [
"express",
"framework",
@@ -22,58 +26,67 @@
"app",
"api"
],
"repository": "visionmedia/express",
"license": "MIT",
"dependencies": {
"accepts": "~1.0.7",
"buffer-crc32": "0.2.3",
"debug": "1.0.2",
"depd": "0.3.0",
"escape-html": "1.0.1",
"finalhandler": "0.0.2",
"media-typer": "0.2.0",
"methods": "1.0.1",
"parseurl": "1.0.1",
"proxy-addr": "1.0.1",
"range-parser": "1.0.0",
"send": "0.5.0",
"serve-static": "~1.3.0",
"type-is": "~1.3.2",
"vary": "0.1.0",
"cookie": "0.1.2",
"fresh": "0.2.2",
"cookie-signature": "1.0.4",
"merge-descriptors": "0.0.2",
"accepts": "~1.3.3",
"array-flatten": "1.1.1",
"content-disposition": "0.5.2",
"content-type": "~1.0.2",
"cookie": "0.3.1",
"cookie-signature": "1.0.6",
"debug": "~2.2.0",
"depd": "~1.1.0",
"encodeurl": "~1.0.1",
"escape-html": "~1.0.3",
"etag": "~1.7.0",
"finalhandler": "0.5.1",
"fresh": "0.3.0",
"merge-descriptors": "1.0.1",
"methods": "~1.1.2",
"on-finished": "~2.3.0",
"parseurl": "~1.3.1",
"path-to-regexp": "0.1.7",
"proxy-addr": "~1.1.3",
"qs": "6.2.0",
"range-parser": "~1.2.0",
"send": "0.14.2",
"serve-static": "~1.11.2",
"type-is": "~1.6.14",
"utils-merge": "1.0.0",
"qs": "0.6.6",
"path-to-regexp": "0.1.2"
"vary": "~1.1.0"
},
"devDependencies": {
"after": "0.8.1",
"istanbul": "0.2.14",
"mocha": "~1.20.1",
"should": "~4.0.4",
"supertest": "~0.13.0",
"connect-redis": "~2.0.0",
"ejs": "~1.0.0",
"jade": "~1.3.1",
"marked": "0.3.2",
"hjs": "~0.0.6",
"body-parser": "~1.4.3",
"cookie-parser": "~1.3.1",
"express-session": "~1.6.1",
"method-override": "2.0.2",
"multiparty": "~3.3.0",
"morgan": "1.1.1",
"vhost": "2.0.0"
"after": "0.8.2",
"body-parser": "1.16.0",
"cookie-parser": "~1.4.3",
"ejs": "2.5.5",
"express-session": "1.15.0",
"istanbul": "0.4.5",
"marked": "0.3.6",
"method-override": "~2.3.6",
"mocha": "3.2.0",
"morgan": "~1.7.0",
"multiparty": "4.1.3",
"should": "11.2.0",
"supertest": "1.2.0",
"connect-redis": "~2.4.1",
"cookie-session": "~1.2.0",
"jade": "~1.11.0",
"vhost": "~3.0.2"
},
"engines": {
"node": ">= 0.10.0"
},
"files": [
"LICENSE",
"History.md",
"Readme.md",
"index.js",
"lib/"
],
"scripts": {
"prepublish": "npm prune",
"test": "mocha --require test/support/env --reporter dot --check-leaks test/ test/acceptance/",
"test": "mocha --require test/support/env --reporter spec --bail --check-leaks test/ test/acceptance/",
"test-ci": "istanbul cover node_modules/mocha/bin/_mocha --report lcovonly -- --require test/support/env --reporter spec --check-leaks test/ test/acceptance/",
"test-cov": "istanbul cover node_modules/mocha/bin/_mocha -- --require test/support/env --reporter dot --check-leaks test/ test/acceptance/",
"test-travis": "istanbul cover node_modules/mocha/bin/_mocha --report lcovonly -- --require test/support/env --reporter spec --check-leaks test/ test/acceptance/"
"test-tap": "mocha --require test/support/env --reporter tap --check-leaks test/ test/acceptance/"
}
}

View File

@@ -1,65 +0,0 @@
/**
* Module dependencies.
*/
var express = require('../');
var app = express()
, blog = express()
, admin = express();
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);

View File

@@ -1 +0,0 @@
p Hello

View File

@@ -1,4 +1,5 @@
var after = require('after');
var should = require('should');
var express = require('../')
, Route = express.Route
@@ -6,170 +7,190 @@ var express = require('../')
, assert = require('assert');
describe('Route', function(){
it('should work without handlers', function(done) {
var req = { method: 'GET', url: '/' }
var route = new Route('/foo')
route.dispatch(req, {}, done)
})
describe('.all', function(){
it('should add handler', function(done){
var req = { method: 'GET', url: '/' };
var route = new Route('/foo');
route.all(function(req, res, next) {
assert.equal(req.a, 1);
assert.equal(res.b, 2);
req.called = true;
next();
});
route.dispatch({ a:1, method: 'GET' }, { b:2 }, done);
route.dispatch(req, {}, function (err) {
if (err) return done(err);
should(req.called).be.ok;
done();
});
})
it('should handle VERBS', function(done) {
var route = new Route('/foo');
var count = 0;
var route = new Route('/foo');
var cb = after(methods.length, function (err) {
if (err) return done(err);
count.should.equal(methods.length);
done();
});
route.all(function(req, res, next) {
count++;
next();
});
methods.forEach(function testMethod(method) {
route.dispatch({ method: method }, {});
var req = { method: method, url: '/' };
route.dispatch(req, {}, cb);
});
assert.equal(count, methods.length);
done();
})
it('should stack', function(done) {
var req = { count: 0, method: 'GET', url: '/' };
var route = new Route('/foo');
var count = 0;
route.all(function(req, res, next) {
count++;
req.count++;
next();
});
route.all(function(req, res, next) {
count++;
req.count++;
next();
});
route.dispatch({ method: 'GET' }, {}, function(err) {
assert.ifError(err);
count++;
route.dispatch(req, {}, function (err) {
if (err) return done(err);
req.count.should.equal(2);
done();
});
assert.equal(count, 3);
done();
})
})
describe('.VERB', function(){
it('should support .get', function(done){
var req = { method: 'GET', url: '/' };
var route = new Route('');
var count = 0;
route.get(function(req, res, next) {
count++;
req.called = true;
next();
})
route.dispatch({ method: 'GET' }, {});
assert(count);
done();
route.dispatch(req, {}, function (err) {
if (err) return done(err);
should(req.called).be.ok;
done();
});
})
it('should limit to just .VERB', function(done){
var req = { method: 'POST', url: '/' };
var route = new Route('');
route.get(function(req, res, next) {
assert(false);
done();
throw new Error('not me!');
})
route.post(function(req, res, next) {
assert(true);
req.called = true;
next();
})
route.dispatch({ method: 'post' }, {});
done();
route.dispatch(req, {}, function (err) {
if (err) return done(err);
should(req.called).be.true;
done();
});
})
it('should allow fallthrough', function(done){
var req = { order: '', method: 'GET', url: '/' };
var route = new Route('');
var order = '';
route.get(function(req, res, next) {
order += 'a';
req.order += 'a';
next();
})
route.all(function(req, res, next) {
order += 'b';
req.order += 'b';
next();
});
route.get(function(req, res, next) {
order += 'c';
req.order += 'c';
next();
})
route.dispatch({ method: 'get' }, {});
assert.equal(order, 'abc');
done();
route.dispatch(req, {}, function (err) {
if (err) return done(err);
req.order.should.equal('abc');
done();
});
})
})
describe('errors', function(){
it('should handle errors via arity 4 functions', function(done){
var req = { order: '', method: 'GET', url: '/' };
var route = new Route('');
var order = '';
route.all(function(req, res, next){
next(new Error('foobar'));
});
route.all(function(req, res, next){
order += '0';
req.order += '0';
next();
});
route.all(function(err, req, res, next){
order += 'a';
req.order += 'a';
next(err);
});
route.all(function(err, req, res, next){
assert.equal(err.message, 'foobar');
assert.equal(order, 'a');
route.dispatch(req, {}, function (err) {
should(err).be.ok;
should(err.message).equal('foobar');
req.order.should.equal('a');
done();
});
route.dispatch({ method: 'get' }, {});
})
it('should handle throw', function(done) {
var req = { order: '', method: 'GET', url: '/' };
var route = new Route('');
var order = '';
route.all(function(req, res, next){
throw new Error('foobar');
});
route.all(function(req, res, next){
order += '0';
req.order += '0';
next();
});
route.all(function(err, req, res, next){
order += 'a';
req.order += 'a';
next(err);
});
route.all(function(err, req, res, next){
assert.equal(err.message, 'foobar');
assert.equal(order, 'a');
route.dispatch(req, {}, function (err) {
should(err).be.ok;
should(err.message).equal('foobar');
req.order.should.equal('a');
done();
});
route.dispatch({ method: 'get' }, {});
});
it('should handle throwing inside error handlers', function(done) {
var req = { method: 'GET', url: '/' };
var route = new Route('');
route.get(function(req, res, next){
@@ -181,21 +202,26 @@ describe('Route', function(){
});
route.get(function(err, req, res, next){
assert.equal(err.message, 'oops');
done();
req.message = err.message;
next();
});
route.dispatch({ url: '/', method: 'GET' }, {});
route.dispatch(req, {}, function (err) {
if (err) return done(err);
should(req.message).equal('oops');
done();
});
});
it('should handle throw in .all', function(done) {
var req = { method: 'GET', url: '/' };
var route = new Route('');
route.all(function(req, res, next){
throw new Error('boom!');
});
route.dispatch({ url: '/', method: 'GET' }, {}, function(err){
route.dispatch(req, {}, function(err){
should(err).be.ok;
err.message.should.equal('boom!');
done();
@@ -203,6 +229,7 @@ describe('Route', function(){
});
it('should handle single error handler', function(done) {
var req = { method: 'GET', url: '/' };
var route = new Route('');
route.all(function(err, req, res, next){
@@ -210,7 +237,7 @@ describe('Route', function(){
true.should.be.false;
});
route.dispatch({ url: '/', method: 'GET' }, {}, done);
route.dispatch(req, {}, done);
});
})
})

View File

@@ -43,6 +43,31 @@ describe('Router', function(){
router.handle({ url: '/test/route', method: 'GET' }, { end: done });
});
it('should handle blank URL', function(done){
var router = new Router();
router.use(function (req, res) {
false.should.be.true;
});
router.handle({ url: '', method: 'GET' }, {}, done);
});
it('should not stack overflow with many registered routes', function(done){
var handler = function(req, res){ res.end(new Error('wrong handler')) };
var router = new Router();
for (var i = 0; i < 6000; i++) {
router.get('/thing' + i, handler)
}
router.get('/', function (req, res) {
res.end();
});
router.handle({ url: '/', method: 'GET' }, { end: done });
});
describe('.handle', function(){
it('should dispatch', function(done){
var router = new Router();
@@ -174,6 +199,128 @@ describe('Router', function(){
});
})
describe('FQDN', function () {
it('should not obscure FQDNs', function (done) {
var request = { hit: 0, url: 'http://example.com/foo', method: 'GET' };
var router = new Router();
router.use(function (req, res, next) {
assert.equal(req.hit++, 0);
assert.equal(req.url, 'http://example.com/foo');
next();
});
router.handle(request, {}, function (err) {
if (err) return done(err);
assert.equal(request.hit, 1);
done();
});
});
it('should ignore FQDN in search', function (done) {
var request = { hit: 0, url: '/proxy?url=http://example.com/blog/post/1', method: 'GET' };
var router = new Router();
router.use('/proxy', function (req, res, next) {
assert.equal(req.hit++, 0);
assert.equal(req.url, '/?url=http://example.com/blog/post/1');
next();
});
router.handle(request, {}, function (err) {
if (err) return done(err);
assert.equal(request.hit, 1);
done();
});
});
it('should ignore FQDN in path', function (done) {
var request = { hit: 0, url: '/proxy/http://example.com/blog/post/1', method: 'GET' };
var router = new Router();
router.use('/proxy', function (req, res, next) {
assert.equal(req.hit++, 0);
assert.equal(req.url, '/http://example.com/blog/post/1');
next();
});
router.handle(request, {}, function (err) {
if (err) return done(err);
assert.equal(request.hit, 1);
done();
});
});
it('should adjust FQDN req.url', function (done) {
var request = { hit: 0, url: 'http://example.com/blog/post/1', method: 'GET' };
var router = new Router();
router.use('/blog', function (req, res, next) {
assert.equal(req.hit++, 0);
assert.equal(req.url, 'http://example.com/post/1');
next();
});
router.handle(request, {}, function (err) {
if (err) return done(err);
assert.equal(request.hit, 1);
done();
});
});
it('should adjust FQDN req.url with multiple handlers', function (done) {
var request = { hit: 0, url: 'http://example.com/blog/post/1', method: 'GET' };
var router = new Router();
router.use(function (req, res, next) {
assert.equal(req.hit++, 0);
assert.equal(req.url, 'http://example.com/blog/post/1');
next();
});
router.use('/blog', function (req, res, next) {
assert.equal(req.hit++, 1);
assert.equal(req.url, 'http://example.com/post/1');
next();
});
router.handle(request, {}, function (err) {
if (err) return done(err);
assert.equal(request.hit, 2);
done();
});
});
it('should adjust FQDN req.url with multiple routed handlers', function (done) {
var request = { hit: 0, url: 'http://example.com/blog/post/1', method: 'GET' };
var router = new Router();
router.use('/blog', function (req, res, next) {
assert.equal(req.hit++, 0);
assert.equal(req.url, 'http://example.com/post/1');
next();
});
router.use('/blog', function (req, res, next) {
assert.equal(req.hit++, 1);
assert.equal(req.url, 'http://example.com/post/1');
next();
});
router.use(function (req, res, next) {
assert.equal(req.hit++, 2);
assert.equal(req.url, 'http://example.com/blog/post/1');
next();
});
router.handle(request, {}, function (err) {
if (err) return done(err);
assert.equal(request.hit, 3);
done();
});
});
})
describe('.all', function() {
it('should support using .all to capture all http verbs', function(done){
var router = new Router();
@@ -192,6 +339,43 @@ describe('Router', function(){
})
})
describe('.use', function() {
it('should require arguments', function(){
var router = new Router();
router.use.bind(router).should.throw(/requires middleware function/)
})
it('should not accept non-functions', function(){
var router = new Router();
router.use.bind(router, '/', 'hello').should.throw(/requires middleware function.*string/)
router.use.bind(router, '/', 5).should.throw(/requires middleware function.*number/)
router.use.bind(router, '/', null).should.throw(/requires middleware function.*Null/)
router.use.bind(router, '/', new Date()).should.throw(/requires middleware function.*Date/)
})
it('should accept array of middleware', function(done){
var count = 0;
var router = new Router();
function fn1(req, res, next){
assert.equal(++count, 1);
next();
}
function fn2(req, res, next){
assert.equal(++count, 2);
next();
}
router.use([fn1, fn2], function(req, res){
assert.equal(++count, 3);
done();
});
router.handle({ url: '/foo', method: 'GET' }, {}, function(){});
})
})
describe('.param', function() {
it('should call param function when routing VERBS', function(done) {
var router = new Router();

View File

@@ -1,4 +1,4 @@
var app = require('../../examples/auth/app')
var app = require('../../examples/auth')
var request = require('supertest')
function getCookie(res) {

View File

@@ -0,0 +1,38 @@
var app = require('../../examples/cookie-sessions')
var request = require('supertest')
describe('cookie-sessions', function () {
describe('GET /', function () {
it('should display no views', function (done) {
request(app)
.get('/')
.expect(200, 'viewed 0 times\n', done)
})
it('should set a session cookie', function (done) {
request(app)
.get('/')
.expect('Set-Cookie', /express:sess=/)
.expect(200, done)
})
it('should display 1 view on revisit', function (done) {
request(app)
.get('/')
.expect(200, 'viewed 0 times\n', function (err, res) {
if (err) return done(err)
request(app)
.get('/')
.set('Cookie', getCookies(res))
.expect(200, 'viewed 1 times\n', done)
})
})
})
})
function getCookies(res) {
return res.headers['set-cookie'].map(function (val) {
return val.split(';')[0]
}).join('; ');
}

View File

@@ -1,6 +1,7 @@
var app = require('../../examples/cookies/app')
var app = require('../../examples/cookies')
, request = require('supertest');
var utils = require('../support/utils');
describe('cookies', function(){
describe('GET /', function(){
@@ -13,10 +14,8 @@ describe('cookies', function(){
it('should respond with no cookies', function(done){
request(app)
.get('/')
.end(function(err, res){
res.headers.should.not.have.property('set-cookie')
done()
})
.expect(utils.shouldNotHaveHeader('Set-Cookie'))
.expect(200, done)
})
it('should respond to cookie', function(done){
@@ -57,20 +56,16 @@ describe('cookies', function(){
.post('/')
.type('urlencoded')
.send({ remember: 1 })
.expect(302, function(err, res){
res.headers.should.have.property('set-cookie')
done()
})
.expect('Set-Cookie', /remember=1/)
.expect(302, done)
})
it('should no set cookie w/o reminder', function(done){
request(app)
.post('/')
.send({})
.expect(302, function(err, res){
res.headers.should.not.have.property('set-cookie')
done()
})
.expect(utils.shouldNotHaveHeader('Set-Cookie'))
.expect(302, done)
})
})
})

View File

@@ -1,5 +1,5 @@
var app = require('../../examples/downloads/app')
var app = require('../../examples/downloads')
, request = require('supertest');
describe('downloads', function(){
@@ -15,11 +15,8 @@ describe('downloads', function(){
it('should have a download header', function(done){
request(app)
.get('/files/amazing.txt')
.end(function(err, res){
res.status.should.equal(200);
res.headers.should.have.property('content-disposition', 'attachment; filename="amazing.txt"')
done()
})
.expect('Content-Disposition', 'attachment; filename="amazing.txt"')
.expect(200, done)
})
})

View File

@@ -0,0 +1,44 @@
var app = require('../../examples/multi-router')
var request = require('supertest')
describe('multi-router', function(){
describe('GET /',function(){
it('should respond with root handler', function(done){
request(app)
.get('/')
.expect(200, 'Hello form root route.', done)
})
})
describe('GET /api/v1/',function(){
it('should respond with APIv1 root handler', function(done){
request(app)
.get('/api/v1/')
.expect(200, 'Hello from APIv1 root route.', done)
})
})
describe('GET /api/v1/users',function(){
it('should respond with users from APIv1', function(done){
request(app)
.get('/api/v1/users')
.expect(200, 'List of APIv1 users.', done)
})
})
describe('GET /api/v2/',function(){
it('should respond with APIv2 root handler', function(done){
request(app)
.get('/api/v2/')
.expect(200, 'Hello from APIv2 root route.', done)
})
})
describe('GET /api/v2/users',function(){
it('should respond with users from APIv2', function(done){
request(app)
.get('/api/v2/users')
.expect(200, 'List of APIv2 users.', done)
})
})
})

View File

@@ -35,7 +35,7 @@ describe('mvc', function(){
.put('/pet/3')
.set('Content-Type', 'application/x-www-form-urlencoded')
.send({ pet: { name: 'Boots' } })
.end(function(err, res){
.expect(302, function (err, res) {
if (err) return done(err);
request(app)
.get('/pet/3/edit')
@@ -105,7 +105,7 @@ describe('mvc', function(){
.put('/user/1')
.set('Content-Type', 'application/x-www-form-urlencoded')
.send({ user: { name: 'Tobo' }})
.end(function(err, res){
.expect(302, function (err, res) {
if (err) return done(err);
request(app)
.get('/user/1/edit')

View File

@@ -1,4 +1,4 @@
var app = require('../../examples/params/app')
var app = require('../../examples/params')
var request = require('supertest')
describe('params', function(){
@@ -21,8 +21,8 @@ describe('params', function(){
describe('GET /user/9', function(){
it('should fail to find user', function(done){
request(app)
.get('/user/9')
.expect(/failed to find user/,done)
.get('/user/9')
.expect(404, /failed to find user/, done)
})
})
@@ -37,8 +37,8 @@ describe('params', function(){
describe('GET /users/foo-bar', function(){
it('should fail integer parsing', function(done){
request(app)
.get('/users/foo-bar')
.expect(/failed to parseInt foo/,done)
.get('/users/foo-bar')
.expect(400, /failed to parseInt foo/, done)
})
})
})

View File

@@ -1,4 +1,4 @@
var app = require('../../examples/resource/app')
var app = require('../../examples/resource')
var request = require('supertest')
describe('resource', function(){

View File

@@ -0,0 +1,97 @@
var app = require('../../examples/route-separation')
var request = require('supertest')
describe('route-separation', function () {
describe('GET /', function () {
it('should respond with index', function (done) {
request(app)
.get('/')
.expect(200, /Route Separation Example/, done)
})
})
describe('GET /users', function () {
it('should list users', function (done) {
request(app)
.get('/users')
.expect(/TJ/)
.expect(/Tobi/)
.expect(200, done)
})
})
describe('GET /user/:id', function () {
it('should get a user', function (done) {
request(app)
.get('/user/0')
.expect(200, /Viewing user TJ/, done)
})
it('should 404 on missing user', function (done) {
request(app)
.get('/user/10')
.expect(404, done)
})
})
describe('GET /user/:id/view', function () {
it('should get a user', function (done) {
request(app)
.get('/user/0/view')
.expect(200, /Viewing user TJ/, done)
})
it('should 404 on missing user', function (done) {
request(app)
.get('/user/10/view')
.expect(404, done)
})
})
describe('GET /user/:id/edit', function () {
it('should get a user to edit', function (done) {
request(app)
.get('/user/0/edit')
.expect(200, /Editing user TJ/, done)
})
})
describe('PUT /user/:id/edit', function () {
it('should edit a user', function (done) {
request(app)
.put('/user/0/edit')
.set('Content-Type', 'application/x-www-form-urlencoded')
.send({ user: { name: 'TJ', email: 'tj-invalid@vision-media.ca' } })
.expect(302, function (err) {
if (err) return done(err)
request(app)
.get('/user/0')
.expect(200, /tj-invalid@vision-media\.ca/, done)
})
})
})
describe('POST /user/:id/edit?_method=PUT', function () {
it('should edit a user', function (done) {
request(app)
.post('/user/1/edit?_method=PUT')
.set('Content-Type', 'application/x-www-form-urlencoded')
.send({ user: { name: 'Tobi', email: 'tobi-invalid@vision-media.ca' } })
.expect(302, function (err) {
if (err) return done(err)
request(app)
.get('/user/1')
.expect(200, /tobi-invalid@vision-media\.ca/, done)
})
})
})
describe('GET /posts', function () {
it('should get a list of posts', function (done) {
request(app)
.get('/posts')
.expect(200, /Posts/, done)
})
})
})

View File

@@ -53,7 +53,7 @@ describe('web-service', function(){
.get('/api/repos?api-key=foo')
.expect('Content-Type', 'application/json; charset=utf-8')
.expect(/"name":"express"/)
.expect(/"url":"http:\/\/github.com\/visionmedia\/express"/)
.expect(/"url":"http:\/\/github.com\/expressjs\/express"/)
.expect(200, done)
})
})

View File

@@ -19,7 +19,7 @@ describe('app.all()', function(){
});
})
it('should ', function(done){
it('should run the callback for a method just once', function(done){
var app = express()
, n = 0;

View File

@@ -12,7 +12,7 @@ describe('app', function(){
it('should be callable', function(){
var app = express();
assert(typeof app, 'function');
assert.equal(typeof app, 'function');
})
it('should 404 without routes', function(done){
@@ -39,16 +39,19 @@ describe('app.parent', function(){
describe('app.mountpath', function(){
it('should return the mounted path', function(){
var app = express()
, blog = express()
, blogAdmin = express();
var admin = express();
var app = express();
var blog = express();
var fallback = express();
app.use('/blog', blog);
blog.use('/admin', blogAdmin);
app.use(fallback);
blog.use('/admin', admin);
admin.mountpath.should.equal('/admin');
app.mountpath.should.equal('/');
blog.mountpath.should.equal('/blog');
blogAdmin.mountpath.should.equal('/admin');
fallback.mountpath.should.equal('/');
})
})

View File

@@ -12,8 +12,22 @@ describe('OPTIONS', function(){
request(app)
.options('/users')
.expect('GET,PUT')
.expect('Allow', 'GET,PUT', done);
.expect('Allow', 'GET,HEAD,PUT')
.expect(200, 'GET,HEAD,PUT', done);
})
it('should only include each method once', function(done){
var app = express();
app.del('/', function(){});
app.get('/users', function(req, res){});
app.put('/users', function(req, res){});
app.get('/users', function(req, res){});
request(app)
.options('/users')
.expect('Allow', 'GET,HEAD,PUT')
.expect(200, 'GET,HEAD,PUT', done);
})
it('should not be affected by app.all', function(done){
@@ -30,8 +44,8 @@ describe('OPTIONS', function(){
request(app)
.options('/users')
.expect('x-hit', '1')
.expect('allow', 'GET,PUT')
.expect(200, 'GET,PUT', done);
.expect('Allow', 'GET,HEAD,PUT')
.expect(200, 'GET,HEAD,PUT', done);
})
it('should not respond if the path is not defined', function(done){
@@ -54,8 +68,30 @@ describe('OPTIONS', function(){
request(app)
.options('/other')
.expect('GET')
.expect('Allow', 'GET', done);
.expect('Allow', 'GET,HEAD')
.expect(200, 'GET,HEAD', done);
})
describe('when error occurs in response handler', function () {
it('should pass error to callback', function (done) {
var app = express();
var router = express.Router();
router.get('/users', function(req, res){});
app.use(function (req, res, next) {
res.writeHead(200);
next();
});
app.use(router);
app.use(function (err, req, res, next) {
res.end('true');
});
request(app)
.options('/users')
.expect(200, 'true', done)
})
})
})

View File

@@ -237,6 +237,27 @@ describe('app', function(){
.expect(500, done);
})
it('should catch thrown secondary error', function(done){
var app = express();
app.param('id', function(req, res, next, val){
process.nextTick(next);
});
app.param('id', function(req, res, next, id){
throw new Error('err!');
});
app.get('/user/:id', function(req, res){
var id = req.params.id;
res.send('' + id);
});
request(app)
.get('/user/123')
.expect(500, done);
})
it('should defer to next route', function(done){
var app = express();
@@ -282,5 +303,65 @@ describe('app', function(){
.get('/user/new')
.expect('get.new', done);
})
it('should not call when values differ on error', function(done) {
var app = express();
var called = 0;
var count = 0;
app.param('user', function(req, res, next, user) {
called++;
if (user === 'foo') throw new Error('err!');
req.user = user;
next();
});
app.get('/:user/bob', function(req, res, next) {
count++;
next();
});
app.get('/foo/:user', function(req, res, next) {
count++;
next();
});
app.use(function(err, req, res, next) {
res.status(500);
res.send([count, called, err.message].join(' '));
});
request(app)
.get('/foo/bob')
.expect(500, '0 1 err!', done)
});
it('should call when values differ when using "next"', function(done) {
var app = express();
var called = 0;
var count = 0;
app.param('user', function(req, res, next, user) {
called++;
if (user === 'foo') return next('route');
req.user = user;
next();
});
app.get('/:user/bob', function(req, res, next) {
count++;
next();
});
app.get('/foo/:user', function(req, res, next) {
count++;
next();
});
app.use(function(req, res) {
res.end([count, called, req.user].join(' '));
});
request(app)
.get('/foo/bob')
.expect('1 2 bob', done);
})
})
})

View File

@@ -1,14 +1,15 @@
var express = require('../');
var express = require('..');
var tmpl = require('./support/tmpl');
describe('app', function(){
describe('.render(name, fn)', function(){
it('should support absolute paths', function(done){
var app = express();
var app = createApp();
app.locals.user = { name: 'tobi' };
app.render(__dirname + '/fixtures/user.jade', function(err, str){
app.render(__dirname + '/fixtures/user.tmpl', function (err, str) {
if (err) return done(err);
str.should.equal('<p>tobi</p>');
done();
@@ -16,9 +17,9 @@ describe('app', function(){
})
it('should support absolute paths with "view engine"', function(done){
var app = express();
var app = createApp();
app.set('view engine', 'jade');
app.set('view engine', 'tmpl');
app.locals.user = { name: 'tobi' };
app.render(__dirname + '/fixtures/user', function(err, str){
@@ -29,12 +30,12 @@ describe('app', function(){
})
it('should expose app.locals', function(done){
var app = express();
var app = createApp();
app.set('views', __dirname + '/fixtures');
app.locals.user = { name: 'tobi' };
app.render('user.jade', function(err, str){
app.render('user.tmpl', function (err, str) {
if (err) return done(err);
str.should.equal('<p>tobi</p>');
done();
@@ -42,12 +43,12 @@ describe('app', function(){
})
it('should support index.<engine>', function(done){
var app = express();
var app = createApp();
app.set('views', __dirname + '/fixtures');
app.set('view engine', 'jade');
app.set('view engine', 'tmpl');
app.render('blog/post', function(err, str){
app.render('blog/post', function (err, str) {
if (err) return done(err);
str.should.equal('<h1>blog post</h1>');
done();
@@ -77,10 +78,11 @@ describe('app', function(){
describe('when the file does not exist', function(){
it('should provide a helpful error', function(done){
var app = express();
var app = createApp();
app.set('views', __dirname + '/fixtures');
app.render('rawr.jade', function(err){
err.message.should.equal('Failed to lookup view "rawr.jade" in views directory "' + __dirname + '/fixtures"');
app.render('rawr.tmpl', function (err) {
err.message.should.equal('Failed to lookup view "rawr.tmpl" in views directory "' + __dirname + '/fixtures"');
done();
});
})
@@ -88,11 +90,11 @@ describe('app', function(){
describe('when an error occurs', function(){
it('should invoke the callback', function(done){
var app = express();
var app = createApp();
app.set('views', __dirname + '/fixtures');
app.render('user.jade', function(err, str){
app.render('user.tmpl', function (err, str) {
// nextTick to prevent cyclic
process.nextTick(function(){
err.message.should.match(/Cannot read property '[^']+' of undefined/);
@@ -104,11 +106,11 @@ describe('app', function(){
describe('when an extension is given', function(){
it('should render the template', function(done){
var app = express();
var app = createApp();
app.set('views', __dirname + '/fixtures');
app.render('email.jade', function(err, str){
app.render('email.tmpl', function (err, str) {
if (err) return done(err);
str.should.equal('<p>This is an email</p>');
done();
@@ -118,9 +120,9 @@ describe('app', function(){
describe('when "view engine" is given', function(){
it('should render the template', function(done){
var app = express();
var app = createApp();
app.set('view engine', 'jade');
app.set('view engine', 'tmpl');
app.set('views', __dirname + '/fixtures');
app.render('email', function(err, str){
@@ -131,6 +133,64 @@ describe('app', function(){
})
})
describe('when "views" is given', function(){
it('should lookup the file in the path', function(done){
var app = createApp();
app.set('views', __dirname + '/fixtures/default_layout');
app.locals.user = { name: 'tobi' };
app.render('user.tmpl', function (err, str) {
if (err) return done(err);
str.should.equal('<p>tobi</p>');
done();
})
})
describe('when array of paths', function(){
it('should lookup the file in the path', function(done){
var app = createApp();
var views = [__dirname + '/fixtures/local_layout', __dirname + '/fixtures/default_layout'];
app.set('views', views);
app.locals.user = { name: 'tobi' };
app.render('user.tmpl', function (err, str) {
if (err) return done(err);
str.should.equal('<span>tobi</span>');
done();
})
})
it('should lookup in later paths until found', function(done){
var app = createApp();
var views = [__dirname + '/fixtures/local_layout', __dirname + '/fixtures/default_layout'];
app.set('views', views);
app.locals.name = 'tobi';
app.render('name.tmpl', function (err, str) {
if (err) return done(err);
str.should.equal('<p>tobi</p>');
done();
})
})
it('should error if file does not exist', function(done){
var app = createApp();
var views = [__dirname + '/fixtures/local_layout', __dirname + '/fixtures/default_layout'];
app.set('views', views);
app.locals.name = 'tobi';
app.render('pet.tmpl', function (err, str) {
err.message.should.equal('Failed to lookup view "pet.tmpl" in views directories "' + __dirname + '/fixtures/local_layout" or "' + __dirname + '/fixtures/default_layout"');
done();
})
})
})
})
describe('when a "view" constructor is given', function(){
it('should create an instance of it', function(done){
var app = express();
@@ -219,13 +279,13 @@ describe('app', function(){
describe('.render(name, options, fn)', function(){
it('should render the template', function(done){
var app = express();
var app = createApp();
app.set('views', __dirname + '/fixtures');
var user = { name: 'tobi' };
app.render('user.jade', { user: user }, function(err, str){
app.render('user.tmpl', { user: user }, function (err, str) {
if (err) return done(err);
str.should.equal('<p>tobi</p>');
done();
@@ -233,12 +293,12 @@ describe('app', function(){
})
it('should expose app.locals', function(done){
var app = express();
var app = createApp();
app.set('views', __dirname + '/fixtures');
app.locals.user = { name: 'tobi' };
app.render('user.jade', {}, function(err, str){
app.render('user.tmpl', {}, function (err, str) {
if (err) return done(err);
str.should.equal('<p>tobi</p>');
done();
@@ -246,13 +306,13 @@ describe('app', function(){
})
it('should give precedence to app.render() locals', function(done){
var app = express();
var app = createApp();
app.set('views', __dirname + '/fixtures');
app.locals.user = { name: 'tobi' };
var jane = { name: 'jane' };
app.render('user.jade', { user: jane }, function(err, str){
app.render('user.tmpl', { user: jane }, function (err, str) {
if (err) return done(err);
str.should.equal('<p>jane</p>');
done();
@@ -292,3 +352,11 @@ describe('app', function(){
})
})
})
function createApp() {
var app = express();
app.engine('.tmpl', tmpl);
return app;
}

View File

@@ -1,4 +1,5 @@
var after = require('after');
var express = require('../')
, request = require('supertest')
, assert = require('assert')
@@ -10,7 +11,7 @@ describe('app.router', function(){
var router = new express.Router();
function handler1(req, res, next){
res.setHeader('x-user-id', req.params.id);
res.setHeader('x-user-id', String(req.params.id));
next()
}
@@ -19,7 +20,7 @@ describe('app.router', function(){
}
router.use(function(req, res, next){
res.setHeader('x-router', req.params.id);
res.setHeader('x-router', String(req.params.id));
next();
});
@@ -32,7 +33,7 @@ describe('app.router', function(){
.expect(200, '1', done);
})
describe('methods supported', function(){
describe('methods', function(){
methods.concat('del').forEach(function(method){
if (method === 'connect') return;
@@ -58,6 +59,35 @@ describe('app.router', function(){
app[method].bind(app, '/', 3).should.throw(/Number/);
})
});
it('should re-route when method is altered', function (done) {
var app = express();
var cb = after(3, done);
app.use(function (req, res, next) {
if (req.method !== 'POST') return next();
req.method = 'DELETE';
res.setHeader('X-Method-Altered', '1');
next();
});
app.delete('/', function (req, res) {
res.end('deleted everything');
});
request(app)
.get('/')
.expect(404, 'Cannot GET /\n', cb);
request(app)
.delete('/')
.expect(200, 'deleted everything', cb);
request(app)
.post('/')
.expect('X-Method-Altered', '1')
.expect(200, 'deleted everything', cb);
});
})
describe('decode querystring', function(){
@@ -290,6 +320,22 @@ describe('app.router', function(){
.expect(200, '[["0","10"],["1","tj"],["2","profile"]]', done);
})
it('should merge numeric indices req.params when parent has same number', function(done){
var app = express();
var router = new express.Router({ mergeParams: true });
router.get('/name:(\\w+)', function(req, res){
var keys = Object.keys(req.params).sort();
res.send(keys.map(function(k){ return [k, req.params[k]] }));
});
app.use('/user/id:(\\d+)', router);
request(app)
.get('/user/id:10/name:tj')
.expect(200, '[["0","10"],["1","tj"]]', done);
})
it('should ignore invalid incoming req.params', function(done){
var app = express();
var router = new express.Router({ mergeParams: true });
@@ -308,6 +354,26 @@ describe('app.router', function(){
.get('/user/tj')
.expect(200, '[["name","tj"]]', done);
})
it('should restore req.params', function(done){
var app = express();
var router = new express.Router({ mergeParams: true });
router.get('/user:(\\w+)/*', function (req, res, next) {
next();
});
app.use('/user/id:(\\d+)', function (req, res, next) {
router(req, res, function (err) {
var keys = Object.keys(req.params).sort();
res.send(keys.map(function(k){ return [k, req.params[k]] }));
});
});
request(app)
.get('/user/id:42/user:tj/profile')
.expect(200, '[["0","42"]]', done);
})
})
describe('trailing slashes', function(){
@@ -338,6 +404,46 @@ describe('app.router', function(){
.expect('tj', done);
})
it('should pass-though middleware', function(done){
var app = express();
app.enable('strict routing');
app.use(function (req, res, next) {
res.setHeader('x-middleware', 'true');
next();
});
app.get('/user/', function(req, res){
res.end('tj');
});
request(app)
.get('/user/')
.expect('x-middleware', 'true')
.expect(200, 'tj', done);
})
it('should pass-though mounted middleware', function(done){
var app = express();
app.enable('strict routing');
app.use('/user/', function (req, res, next) {
res.setHeader('x-middleware', 'true');
next();
});
app.get('/user/test/', function(req, res){
res.end('tj');
});
request(app)
.get('/user/test/')
.expect('x-middleware', 'true')
.expect(200, 'tj', done);
})
it('should match no slashes', function(done){
var app = express();
@@ -352,6 +458,48 @@ describe('app.router', function(){
.expect('tj', done);
})
it('should match middleware when omitting the trailing slash', function(done){
var app = express();
app.enable('strict routing');
app.use('/user/', function(req, res){
res.end('tj');
});
request(app)
.get('/user')
.expect(200, 'tj', done);
})
it('should match middleware', function(done){
var app = express();
app.enable('strict routing');
app.use('/user', function(req, res){
res.end('tj');
});
request(app)
.get('/user')
.expect(200, 'tj', done);
})
it('should match middleware when adding the trailing slash', function(done){
var app = express();
app.enable('strict routing');
app.use('/user', function(req, res){
res.end('tj');
});
request(app)
.get('/user/')
.expect(200, 'tj', done);
})
it('should fail when omitting the trailing slash', function(done){
var app = express();
@@ -518,7 +666,7 @@ describe('app.router', function(){
.expect('', done);
})
it('should require a preceeding /', function(done){
it('should require a preceding /', function(done){
var app = express();
app.get('/file/*', function(req, res){
@@ -529,6 +677,30 @@ describe('app.router', function(){
.get('/file')
.expect(404, done);
})
it('should keep correct parameter indexes', function(done){
var app = express();
app.get('/*/user/:id', function (req, res) {
res.send(req.params);
});
request(app)
.get('/1/user/2')
.expect(200, '{"0":"1","id":"2"}', done);
})
it('should work within arrays', function(done){
var app = express();
app.get(['/user/:id', '/foo/*', '/:bar'], function (req, res) {
res.send(req.params.bar);
});
request(app)
.get('/test')
.expect(200, 'test', done);
})
})
describe(':name', function(){
@@ -567,6 +739,52 @@ describe('app.router', function(){
.get('/user/tj/edit')
.expect('editing tj', done);
})
it('should work following a partial capture group', function(done){
var app = express();
var cb = after(2, done);
app.get('/user(s)?/:user/:op', function(req, res){
res.end(req.params.op + 'ing ' + req.params.user + (req.params[0] ? ' (old)' : ''));
});
request(app)
.get('/user/tj/edit')
.expect('editing tj', cb);
request(app)
.get('/users/tj/edit')
.expect('editing tj (old)', cb);
})
it('should work inside literal parenthesis', function(done){
var app = express();
app.get('/:user\\(:op\\)', function(req, res){
res.end(req.params.op + 'ing ' + req.params.user);
});
request(app)
.get('/tj(edit)')
.expect('editing tj', done);
})
it('should work in array of paths', function(done){
var app = express();
var cb = after(2, done);
app.get(['/user/:user/poke', '/user/:user/pokes'], function(req, res){
res.end('poking ' + req.params.user);
});
request(app)
.get('/user/tj/poke')
.expect('poking tj', cb);
request(app)
.get('/user/tj/pokes')
.expect('poking tj', cb);
})
})
describe(':name?', function(){
@@ -724,6 +942,32 @@ describe('app.router', function(){
done();
})
})
it('should call handler in same route, if exists', function(done){
var app = express();
function fn1(req, res, next) {
next(new Error('boom!'));
}
function fn2(req, res, next) {
res.send('foo here');
}
function fn3(err, req, res, next) {
res.send('route go ' + err.message);
}
app.get('/foo', fn1, fn2, fn3);
app.use(function (err, req, res, next) {
res.end('error!');
})
request(app)
.get('/foo')
.expect('route go boom!', done)
})
})
it('should allow rewriting of the url', function(done){

View File

@@ -3,6 +3,22 @@ var express = require('../')
describe('app', function(){
describe('.VERB()', function(){
it('should not get invoked without error handler on error', function(done) {
var app = express();
app.use(function(req, res, next){
next(new Error('boom!'))
});
app.get('/bar', function(req, res){
res.send('hello, world!');
});
request(app)
.post('/bar')
.expect(500, /Error: boom!/, done);
});
it('should only call an error handling routing callback when an error is propagated', function(done){
var app = express();

View File

@@ -1,6 +1,7 @@
var express = require('../')
, request = require('supertest');
var after = require('after');
var express = require('..');
var request = require('supertest');
describe('app', function(){
it('should emit "mount" when mounted', function(done){
@@ -15,11 +16,6 @@ describe('app', function(){
app.use(blog);
})
it('should reject numbers', function(){
var app = express();
app.use.bind(app, 3).should.throw(/Number/);
})
describe('.use(app)', function(){
it('should mount the app', function(done){
var blog = express()
@@ -83,5 +79,449 @@ describe('app', function(){
.get('/post/once-upon-a-time')
.expect('success', done);
})
it('should support mounted app anywhere', function(done){
var cb = after(3, done);
var blog = express()
, other = express()
, app = express();
function fn1(req, res, next) {
res.setHeader('x-fn-1', 'hit');
next();
}
function fn2(req, res, next) {
res.setHeader('x-fn-2', 'hit');
next();
}
blog.get('/', function(req, res){
res.end('success');
});
blog.once('mount', function (parent) {
parent.should.equal(app);
cb();
});
other.once('mount', function (parent) {
parent.should.equal(app);
cb();
});
app.use('/post/:article', fn1, other, fn2, blog);
request(app)
.get('/post/once-upon-a-time')
.expect('x-fn-1', 'hit')
.expect('x-fn-2', 'hit')
.expect('success', cb);
})
})
describe('.use(middleware)', function(){
it('should accept multiple arguments', function (done) {
var app = express();
function fn1(req, res, next) {
res.setHeader('x-fn-1', 'hit');
next();
}
function fn2(req, res, next) {
res.setHeader('x-fn-2', 'hit');
next();
}
app.use(fn1, fn2, function fn3(req, res) {
res.setHeader('x-fn-3', 'hit');
res.end();
});
request(app)
.get('/')
.expect('x-fn-1', 'hit')
.expect('x-fn-2', 'hit')
.expect('x-fn-3', 'hit')
.expect(200, done);
})
it('should invoke middleware for all requests', function (done) {
var app = express();
var cb = after(3, done);
app.use(function (req, res) {
res.send('saw ' + req.method + ' ' + req.url);
});
request(app)
.get('/')
.expect(200, 'saw GET /', cb);
request(app)
.options('/')
.expect(200, 'saw OPTIONS /', cb);
request(app)
.post('/foo')
.expect(200, 'saw POST /foo', cb);
})
it('should accept array of middleware', function (done) {
var app = express();
function fn1(req, res, next) {
res.setHeader('x-fn-1', 'hit');
next();
}
function fn2(req, res, next) {
res.setHeader('x-fn-2', 'hit');
next();
}
function fn3(req, res, next) {
res.setHeader('x-fn-3', 'hit');
res.end();
}
app.use([fn1, fn2, fn3]);
request(app)
.get('/')
.expect('x-fn-1', 'hit')
.expect('x-fn-2', 'hit')
.expect('x-fn-3', 'hit')
.expect(200, done);
})
it('should accept multiple arrays of middleware', function (done) {
var app = express();
function fn1(req, res, next) {
res.setHeader('x-fn-1', 'hit');
next();
}
function fn2(req, res, next) {
res.setHeader('x-fn-2', 'hit');
next();
}
function fn3(req, res, next) {
res.setHeader('x-fn-3', 'hit');
res.end();
}
app.use([fn1, fn2], [fn3]);
request(app)
.get('/')
.expect('x-fn-1', 'hit')
.expect('x-fn-2', 'hit')
.expect('x-fn-3', 'hit')
.expect(200, done);
})
it('should accept nested arrays of middleware', function (done) {
var app = express();
function fn1(req, res, next) {
res.setHeader('x-fn-1', 'hit');
next();
}
function fn2(req, res, next) {
res.setHeader('x-fn-2', 'hit');
next();
}
function fn3(req, res, next) {
res.setHeader('x-fn-3', 'hit');
res.end();
}
app.use([[fn1], fn2], [fn3]);
request(app)
.get('/')
.expect('x-fn-1', 'hit')
.expect('x-fn-2', 'hit')
.expect('x-fn-3', 'hit')
.expect(200, done);
})
})
describe('.use(path, middleware)', function(){
it('should reject missing functions', function () {
var app = express();
app.use.bind(app, '/').should.throw(/requires middleware function/);
})
it('should reject non-functions as middleware', function () {
var app = express();
app.use.bind(app, '/', 'hi').should.throw(/requires middleware function.*string/);
app.use.bind(app, '/', 5).should.throw(/requires middleware function.*number/);
app.use.bind(app, '/', null).should.throw(/requires middleware function.*Null/);
app.use.bind(app, '/', new Date()).should.throw(/requires middleware function.*Date/);
})
it('should strip path from req.url', function (done) {
var app = express();
app.use('/foo', function (req, res) {
res.send('saw ' + req.method + ' ' + req.url);
});
request(app)
.get('/foo/bar')
.expect(200, 'saw GET /bar', done);
})
it('should accept multiple arguments', function (done) {
var app = express();
function fn1(req, res, next) {
res.setHeader('x-fn-1', 'hit');
next();
}
function fn2(req, res, next) {
res.setHeader('x-fn-2', 'hit');
next();
}
app.use('/foo', fn1, fn2, function fn3(req, res) {
res.setHeader('x-fn-3', 'hit');
res.end();
});
request(app)
.get('/foo')
.expect('x-fn-1', 'hit')
.expect('x-fn-2', 'hit')
.expect('x-fn-3', 'hit')
.expect(200, done);
})
it('should invoke middleware for all requests starting with path', function (done) {
var app = express();
var cb = after(3, done);
app.use('/foo', function (req, res) {
res.send('saw ' + req.method + ' ' + req.url);
});
request(app)
.get('/')
.expect(404, cb);
request(app)
.post('/foo')
.expect(200, 'saw POST /', cb);
request(app)
.post('/foo/bar')
.expect(200, 'saw POST /bar', cb);
})
it('should work if path has trailing slash', function (done) {
var app = express();
var cb = after(3, done);
app.use('/foo/', function (req, res) {
res.send('saw ' + req.method + ' ' + req.url);
});
request(app)
.get('/')
.expect(404, cb);
request(app)
.post('/foo')
.expect(200, 'saw POST /', cb);
request(app)
.post('/foo/bar')
.expect(200, 'saw POST /bar', cb);
})
it('should accept array of middleware', function (done) {
var app = express();
function fn1(req, res, next) {
res.setHeader('x-fn-1', 'hit');
next();
}
function fn2(req, res, next) {
res.setHeader('x-fn-2', 'hit');
next();
}
function fn3(req, res, next) {
res.setHeader('x-fn-3', 'hit');
res.end();
}
app.use('/foo', [fn1, fn2, fn3]);
request(app)
.get('/foo')
.expect('x-fn-1', 'hit')
.expect('x-fn-2', 'hit')
.expect('x-fn-3', 'hit')
.expect(200, done);
})
it('should accept multiple arrays of middleware', function (done) {
var app = express();
function fn1(req, res, next) {
res.setHeader('x-fn-1', 'hit');
next();
}
function fn2(req, res, next) {
res.setHeader('x-fn-2', 'hit');
next();
}
function fn3(req, res, next) {
res.setHeader('x-fn-3', 'hit');
res.end();
}
app.use('/foo', [fn1, fn2], [fn3]);
request(app)
.get('/foo')
.expect('x-fn-1', 'hit')
.expect('x-fn-2', 'hit')
.expect('x-fn-3', 'hit')
.expect(200, done);
})
it('should accept nested arrays of middleware', function (done) {
var app = express();
function fn1(req, res, next) {
res.setHeader('x-fn-1', 'hit');
next();
}
function fn2(req, res, next) {
res.setHeader('x-fn-2', 'hit');
next();
}
function fn3(req, res, next) {
res.setHeader('x-fn-3', 'hit');
res.end();
}
app.use('/foo', [fn1, [fn2]], [fn3]);
request(app)
.get('/foo')
.expect('x-fn-1', 'hit')
.expect('x-fn-2', 'hit')
.expect('x-fn-3', 'hit')
.expect(200, done);
})
it('should support array of paths', function (done) {
var app = express();
var cb = after(3, done);
app.use(['/foo/', '/bar'], function (req, res) {
res.send('saw ' + req.method + ' ' + req.url + ' through ' + req.originalUrl);
});
request(app)
.get('/')
.expect(404, cb);
request(app)
.get('/foo')
.expect(200, 'saw GET / through /foo', cb);
request(app)
.get('/bar')
.expect(200, 'saw GET / through /bar', cb);
})
it('should support array of paths with middleware array', function (done) {
var app = express();
var cb = after(2, done);
function fn1(req, res, next) {
res.setHeader('x-fn-1', 'hit');
next();
}
function fn2(req, res, next) {
res.setHeader('x-fn-2', 'hit');
next();
}
function fn3(req, res, next) {
res.setHeader('x-fn-3', 'hit');
res.send('saw ' + req.method + ' ' + req.url + ' through ' + req.originalUrl);
}
app.use(['/foo/', '/bar'], [[fn1], fn2], [fn3]);
request(app)
.get('/foo')
.expect('x-fn-1', 'hit')
.expect('x-fn-2', 'hit')
.expect('x-fn-3', 'hit')
.expect(200, 'saw GET / through /foo', cb);
request(app)
.get('/bar')
.expect('x-fn-1', 'hit')
.expect('x-fn-2', 'hit')
.expect('x-fn-3', 'hit')
.expect(200, 'saw GET / through /bar', cb);
})
it('should support regexp path', function (done) {
var app = express();
var cb = after(4, done);
app.use(/^\/[a-z]oo/, function (req, res) {
res.send('saw ' + req.method + ' ' + req.url + ' through ' + req.originalUrl);
});
request(app)
.get('/')
.expect(404, cb);
request(app)
.get('/foo')
.expect(200, 'saw GET / through /foo', cb);
request(app)
.get('/zoo/bear')
.expect(200, 'saw GET /bear through /zoo/bear', cb);
request(app)
.get('/get/zoo')
.expect(404, cb);
})
it('should support empty string path', function (done) {
var app = express();
app.use('', function (req, res) {
res.send('saw ' + req.method + ' ' + req.url + ' through ' + req.originalUrl);
});
request(app)
.get('/')
.expect(200, 'saw GET / through /', done);
})
})
})

View File

@@ -1,30 +1,36 @@
var express = require('../')
, assert = require('assert');
var assert = require('assert');
var express = require('..');
describe('config', function(){
describe('.set()', function(){
it('should set a value', function(){
describe('config', function () {
describe('.set()', function () {
it('should set a value', function () {
var app = express();
app.set('foo', 'bar').should.equal(app);
app.set('foo', 'bar');
assert.equal(app.get('foo'), 'bar');
})
it('should return the app when undefined', function(){
it('should return the app', function () {
var app = express();
app.set('foo', undefined).should.equal(app);
assert.equal(app.set('foo', 'bar'), app);
})
it('should return the app when undefined', function () {
var app = express();
assert.equal(app.set('foo', undefined), app);
})
describe('"etag"', function(){
it('should throw on bad value', function(){
var app = express()
app.set.bind(app, 'etag', 42).should.throw(/unknown value/)
var app = express();
assert.throws(app.set.bind(app, 'etag', 42), /unknown value/);
})
it('should set "etag fn"', function(){
var app = express()
var fn = function(){}
app.set('etag', fn)
app.get('etag fn').should.equal(fn)
assert.equal(app.get('etag fn'), fn)
})
})
@@ -33,7 +39,7 @@ describe('config', function(){
var app = express()
var fn = function(){}
app.set('trust proxy', fn)
app.get('trust proxy fn').should.equal(fn)
assert.equal(app.get('trust proxy fn'), fn)
})
})
})
@@ -41,34 +47,73 @@ describe('config', function(){
describe('.get()', function(){
it('should return undefined when unset', function(){
var app = express();
assert(undefined === app.get('foo'));
assert.strictEqual(app.get('foo'), undefined);
})
it('should otherwise return the value', function(){
var app = express();
app.set('foo', 'bar');
app.get('foo').should.equal('bar');
assert.equal(app.get('foo'), 'bar');
})
describe('when mounted', function(){
it('should default to the parent app', function(){
var app = express()
, blog = express();
var app = express();
var blog = express();
app.set('title', 'Express');
app.use(blog);
blog.get('title').should.equal('Express');
assert.equal(blog.get('title'), 'Express');
})
it('should given precedence to the child', function(){
var app = express()
, blog = express();
var app = express();
var blog = express();
app.use(blog);
app.set('title', 'Express');
blog.set('title', 'Some Blog');
blog.get('title').should.equal('Some Blog');
assert.equal(blog.get('title'), 'Some Blog');
})
it('should inherit "trust proxy" setting', function () {
var app = express();
var blog = express();
function fn() { return false }
app.set('trust proxy', fn);
assert.equal(app.get('trust proxy'), fn);
assert.equal(app.get('trust proxy fn'), fn);
app.use(blog);
assert.equal(blog.get('trust proxy'), fn);
assert.equal(blog.get('trust proxy fn'), fn);
})
it('should prefer child "trust proxy" setting', function () {
var app = express();
var blog = express();
function fn1() { return false }
function fn2() { return true }
app.set('trust proxy', fn1);
assert.equal(app.get('trust proxy'), fn1);
assert.equal(app.get('trust proxy fn'), fn1);
blog.set('trust proxy', fn2);
assert.equal(blog.get('trust proxy'), fn2);
assert.equal(blog.get('trust proxy fn'), fn2);
app.use(blog);
assert.equal(app.get('trust proxy'), fn1);
assert.equal(app.get('trust proxy fn'), fn1);
assert.equal(blog.get('trust proxy'), fn2);
assert.equal(blog.get('trust proxy fn'), fn2);
})
})
})
@@ -76,42 +121,42 @@ describe('config', function(){
describe('.enable()', function(){
it('should set the value to true', function(){
var app = express();
app.enable('tobi').should.equal(app);
app.get('tobi').should.be.true;
assert.equal(app.enable('tobi'), app);
assert.strictEqual(app.get('tobi'), true);
})
})
describe('.disable()', function(){
it('should set the value to false', function(){
var app = express();
app.disable('tobi').should.equal(app);
app.get('tobi').should.be.false;
assert.equal(app.disable('tobi'), app);
assert.strictEqual(app.get('tobi'), false);
})
})
describe('.enabled()', function(){
it('should default to false', function(){
var app = express();
app.enabled('foo').should.be.false;
assert.strictEqual(app.enabled('foo'), false);
})
it('should return true when set', function(){
var app = express();
app.set('foo', 'bar');
app.enabled('foo').should.be.true;
assert.strictEqual(app.enabled('foo'), true);
})
})
describe('.disabled()', function(){
it('should default to true', function(){
var app = express();
app.disabled('foo').should.be.true;
assert.strictEqual(app.disabled('foo'), true);
})
it('should return false when set', function(){
var app = express();
app.set('foo', 'bar');
app.disabled('foo').should.be.false;
assert.strictEqual(app.disabled('foo'), false);
})
})
})

1
test/fixtures/% of dogs.txt vendored Normal file
View File

@@ -0,0 +1 @@
20%

1
test/fixtures/blog/index.html vendored Normal file
View File

@@ -0,0 +1 @@
<b>index</b>

View File

@@ -1 +0,0 @@
h1 blog post

1
test/fixtures/blog/post/index.tmpl vendored Normal file
View File

@@ -0,0 +1 @@
<h1>blog post</h1>

View File

@@ -0,0 +1 @@
<p>$name</p>

View File

@@ -0,0 +1 @@
<p>$user.name</p>

View File

@@ -1 +0,0 @@
p This is an email

1
test/fixtures/email.tmpl vendored Normal file
View File

@@ -0,0 +1 @@
<p>This is an email</p>

1
test/fixtures/local_layout/user.tmpl vendored Normal file
View File

@@ -0,0 +1 @@
<span>$user.name</span>

View File

@@ -1 +0,0 @@
p= name

1
test/fixtures/name.tmpl vendored Normal file
View File

@@ -0,0 +1 @@
<p>$name</p>

View File

@@ -1 +0,0 @@
p #{first} #{last} is a #{species}

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