Comparar commits
414 Commits
| Autor | SHA1 | Data | |
|---|---|---|---|
| b0da4b1a94 | |||
| 2bc703cfc2 | |||
| c9865b821d | |||
| 9c0de23645 | |||
| b7a38af41d | |||
| 661914781e | |||
| 6e3f3887e9 | |||
| a66d6bb034 | |||
| 2e197e2b98 | |||
| 55d1a4f964 | |||
| 82a7d7a977 | |||
| dae54b456f | |||
| 1b7a044f33 | |||
| 18264403b1 | |||
| 04d43b7039 | |||
| 2dfecfb661 | |||
| 250f1f5f6e | |||
| 3ac718763f | |||
| 05e1555c0d | |||
| 855d1e2bf5 | |||
| f0bfb3b2b2 | |||
| 4b4db0f7fb | |||
| 9bed2b80ee | |||
| bb157c0cbf | |||
| 1ef05d4a28 | |||
| 0b88208022 | |||
| c9d9ed3493 | |||
| bd8b9f5781 | |||
| 9cbcf23df0 | |||
| 36e42db05b | |||
| 2bf6a1d813 | |||
| e8373d3564 | |||
| e218377a3d | |||
| 7d1aed4955 | |||
| b4acbcf1fe | |||
| 50cb62c5d2 | |||
| 4cf868bd74 | |||
| baa5a7c3e9 | |||
| ee228f7aea | |||
| d5b11c7d1b | |||
| ed7db34bab | |||
| 57e45e3af8 | |||
| 1dc46478cb | |||
| 113ed0927d | |||
| ab8be2d741 | |||
| 3b53b11fcd | |||
| 9fb661559b | |||
| 04882cf72c | |||
| 288176bbc9 | |||
| 5638a4fc62 | |||
| 3b4ce91fa3 | |||
| 1c87e5e9a8 | |||
| a887e6a881 | |||
| 69290cad6f | |||
| b66c7da05f | |||
| 92ddf77453 | |||
| 8e2f538983 | |||
| 2817d8caf2 | |||
| b7f08fb159 | |||
| 0c2768f5bd | |||
| 09bede1a92 | |||
| 7059d3b71e | |||
| e5de08faa1 | |||
| e43ff076fd | |||
| 3ea7381dea | |||
| f1c46f51e5 | |||
| 297fb4e0b0 | |||
| 9e406dfee2 | |||
| 30b7aa8a17 | |||
| c1d16e0016 | |||
| 929ffb8d77 | |||
| 197a2e3b54 | |||
| 6cf6c8b918 | |||
| 058d7ec2ea | |||
| 752b5f705e | |||
| e7fa579637 | |||
| 97781d4112 | |||
| 3ddd8e66a7 | |||
| 8a1e865e37 | |||
| e850cb3ea3 | |||
| 13d3efe8df | |||
| d6ecf785a2 | |||
| 19cb39869f | |||
| a38bdf6758 | |||
| bdbdab7fcc | |||
| 5aa9670120 | |||
| 8ad8cb93cc | |||
| 610e172fcf | |||
| 6942070a21 | |||
| e283200511 | |||
| 54a192a5c5 | |||
| c3bd65eda2 | |||
| 7c2ed1d2d6 | |||
| 3de81e0147 | |||
| 8fe1e2a5b4 | |||
| 909dbb81d5 | |||
| 26802a689c | |||
| 37239fb67f | |||
| 018dc40b32 | |||
| 52440955e6 | |||
| c2f3d6ce2b | |||
| be858f5d07 | |||
| 1f14734f91 | |||
| 6d1d694dbb | |||
| ba5c48aa86 | |||
| 320d7807a9 | |||
| 6650a312b7 | |||
| 832c3b3744 | |||
| 76691bfd6b | |||
| 29fe5ea785 | |||
| 7a31a1d311 | |||
| 52a820113f | |||
| aec3428489 | |||
| a10f695b6f | |||
| a3c9eacaf1 | |||
| 19d685b152 | |||
| 8ab44081d4 | |||
| 0431d22822 | |||
| 138d74aefa | |||
| 28562b2cf8 | |||
| e0afda444f | |||
| 5a4cac58af | |||
| 545dca6c4d | |||
| e59a882389 | |||
| ccd9828535 | |||
| 41f0d32355 | |||
| 2f19b4fefc | |||
| cd31cecfd1 | |||
| 2fe46b3905 | |||
| 24974f1f8f | |||
| fd73bd006e | |||
| 7388c2c223 | |||
| e2210b0b92 | |||
| 30919be2a0 | |||
| 10b21b41f7 | |||
| 28b8a3b5f7 | |||
| 8b2f1bba95 | |||
| c805d80a9b | |||
| d876778d22 | |||
| 412e571600 | |||
| 3296ed9cb3 | |||
| 91835e6816 | |||
| f976625281 | |||
| 028d9d8a0c | |||
| 8559c0e2a4 | |||
| 06ead58240 | |||
| 28ca1b5221 | |||
| 6d872e6693 | |||
| 0b09c8981f | |||
| a1d5676ecb | |||
| f862ad29f5 | |||
| 15496da8fd | |||
| 802fb1632c | |||
| 69453ff889 | |||
| 28752cc3c0 | |||
| 9f06d9b03f | |||
| 3fb7c4e1db | |||
| 5fa685b602 | |||
| eb1bbb92c0 | |||
| d0e49f1a8a | |||
| ea2664a4b8 | |||
| da6524bd06 | |||
| a231406931 | |||
| 6d39ed8ef7 | |||
| f2563f4dde | |||
| 3df265b36a | |||
| e382e6adc7 | |||
| 91c71d6c2e | |||
| 0d40c65b7f | |||
| 58f2057ba7 | |||
| 37179109db | |||
| 579857cfaa | |||
| 0b4e2df480 | |||
| 49cc1a70b1 | |||
| f8a33d137a | |||
| 2db135dfc7 | |||
| 99bc628ad1 | |||
| 5ba6c301d7 | |||
| 88273a59f8 | |||
| 2e53cb72ec | |||
| 3b1597d79e | |||
| 776ee26bc3 | |||
| ed273448b9 | |||
| 4bb91b3f67 | |||
| c5f866098e | |||
| 6cfd01be6b | |||
| 53b8e25731 | |||
| 9e684d45bc | |||
| 09d9201787 | |||
| a732d6d471 | |||
| ee9d50c128 | |||
| d1bafa0685 | |||
| 2604be5491 | |||
| c52d9cdfbe | |||
| aab6b7e721 | |||
| d13cea46d5 | |||
| 82731dae6e | |||
| 476fba3e8b | |||
| a566624f2d | |||
| c6d7352f5c | |||
| 771573be30 | |||
| b7afa4f0f4 | |||
| 4a1fa58704 | |||
| 6654b7162c | |||
| f26a3cc806 | |||
| 57e48c4767 | |||
| 66d9a4ad43 | |||
| 78d9c98187 | |||
| b686ec1182 | |||
| 158f452b50 | |||
| 916acd1dd3 | |||
| b4f612474b | |||
| 9a884aa9ee | |||
| db5636199e | |||
| 8211562cf6 | |||
| 9df93d6dec | |||
| 1e251af8d3 | |||
| eed0f598a0 | |||
| ec4d4a792a | |||
| 84e745f67c | |||
| 97edb23dba | |||
| 856782c81c | |||
| a7266392f9 | |||
| 04b0c44bdf | |||
| 99c9eecde5 | |||
| 4d65bbf612 | |||
| 956aa0cfff | |||
| d874476f0b | |||
| 30f9805539 | |||
| 46536dee39 | |||
| 24087d94df | |||
| d02df2ebd5 | |||
| 16ba1f62a3 | |||
| 684dd1a3c6 | |||
| 8bcdcfeedd | |||
| 3bc372aa33 | |||
| fc1c024041 | |||
| 89427228d1 | |||
| 420225f370 | |||
| 44a3fa6359 | |||
| d853c833f0 | |||
| 03a796c460 | |||
| 75e47f2883 | |||
| a4b2e48dfe | |||
| 57cda1578d | |||
| 6b1d7a94ff | |||
| 49abd7bec1 | |||
| 0ebebd80fe | |||
| d157d47c6e | |||
| e3ac2c5b02 | |||
| cd54faa4af | |||
| 5beb1c4e30 | |||
| 4031aaa591 | |||
| ba00e23630 | |||
| 8beb1f21ef | |||
| fa8eec449b | |||
| ab75fa048e | |||
| bb29da5980 | |||
| a4d7b75129 | |||
| 0fdceb3de3 | |||
| 480d0064e1 | |||
| 17bf04d1ef | |||
| 3ab30210a2 | |||
| 14fcfdee7e | |||
| d4e56c1fa2 | |||
| 39ee6f8e79 | |||
| 8d21f1e45c | |||
| 618484a4fe | |||
| 64a234958a | |||
| e4907ce8e8 | |||
| 33eaa8329c | |||
| 3c4fd57e51 | |||
| a1e42ac33f | |||
| ce7d7bfd8d | |||
| 9bd86cdddc | |||
| 0117464ac2 | |||
| 6f6eec7d8d | |||
| a4e93c0fb8 | |||
| e2ad0d3d6e | |||
| 763be5e631 | |||
| c8526932f3 | |||
| 5cf29a3d29 | |||
| 18a3cc03ee | |||
| ea5e254c7d | |||
| 060653bd4c | |||
| b709009bc9 | |||
| b80d7ec257 | |||
| ff0384e610 | |||
| ab9c275bde | |||
| c70db96b06 | |||
| 1c616e29e2 | |||
| cb7518435f | |||
| 79f81c0a25 | |||
| 72b9e48331 | |||
| eba6aa1767 | |||
| 534fbdb307 | |||
| 6b309a4457 | |||
| af5e38c31a | |||
| 4283f38698 | |||
| 2d49c0d1f3 | |||
| a7ca3817db | |||
| 1f044547ee | |||
| 612fc47044 | |||
| 8959ff155b | |||
| dadf57cc8b | |||
| 764b6c61d9 | |||
| 582dadf787 | |||
| 12d97169d7 | |||
| c29cfa823d | |||
| e183a9694e | |||
| d6cb449011 | |||
| 7bf4ad30fc | |||
| b3936b96e5 | |||
| 44d0625e91 | |||
| c492cde048 | |||
| c2fa6cc94d | |||
| 464608025b | |||
| d653d2308b | |||
| a52b1f121c | |||
| 9edd8be520 | |||
| aa1d47600a | |||
| be7ec8b40e | |||
| 8e12dd9c17 | |||
| fee0f0dce0 | |||
| 0dd80e7b50 | |||
| 78d5b72081 | |||
| e0df865401 | |||
| 2abcbed67a | |||
| 02b9d0b2e6 | |||
| 927e181db7 | |||
| dc411b3175 | |||
| 1e870f0f0d | |||
| 3cd01598a5 | |||
| 3b6d683b7f | |||
| eeef763f6d | |||
| 76d3ec583d | |||
| 077d8b9247 | |||
| 92840b9f68 | |||
| bf60d5a041 | |||
| 56ffab045e | |||
| 496ee401d7 | |||
| f0d5b3b368 | |||
| 88072a56ea | |||
| 0d3a637389 | |||
| dc44f3c226 | |||
| 1029b0b97f | |||
| 84f8228b8c | |||
| 968e8f0121 | |||
| 9eb1da4568 | |||
| 315e79e9f0 | |||
| 363d0d4f41 | |||
| 5ac631a270 | |||
| 75fc882001 | |||
| d7cb213eeb | |||
| 568e0d297a | |||
| 8edf358739 | |||
| 40be3ed05d | |||
| 2c174d6b3b | |||
| 60ee465bf7 | |||
| 51210d6b95 | |||
| a6caa267bd | |||
| cdb3e9dc0d | |||
| f2f09767fb | |||
| eec31d7126 | |||
| 3c5ad753b6 | |||
| dd338b5567 | |||
| 1b15af713c | |||
| 89c5affc3b | |||
| 2bba69f633 | |||
| 4403f136b7 | |||
| f7c1c638bb | |||
| f2d7bbe0e9 | |||
| 87468cffce | |||
| 3f7e3a714e | |||
| 38a9caf159 | |||
| 500c8ab4b3 | |||
| c4ad97d555 | |||
| b96401ac83 | |||
| 32a5c9cba5 | |||
| 0217e6ce96 | |||
| 6bebe0837f | |||
| ff1c6f0cfa | |||
| 8ac3e80bf0 | |||
| 3923ec89f7 | |||
| fd8ca32ab2 | |||
| ba2f66d765 | |||
| 056c840a06 | |||
| 20e8f08cb2 | |||
| bac0c64633 | |||
| 48923055eb | |||
| 0f20a5e06a | |||
| 56bfb9249f | |||
| 5ed1544cab | |||
| e5c7be9364 | |||
| 73ce9d028c | |||
| 75debbe5bc | |||
| 5f33d89ea5 | |||
| 42fd29efe8 | |||
| 2d91eac811 | |||
| a50f02e87d | |||
| 214f913b0c | |||
| 1021c86300 | |||
| 386516815a | |||
| d5e5647bba | |||
| a861ea7eaf | |||
| cb844132e6 | |||
| 8050308706 | |||
| e79f72bf88 | |||
| 07b6c9f563 | |||
| 8f4e61a474 | |||
| 54d37c60f5 | |||
| a93d375acc | |||
| d66f0e5eb9 | |||
| e84db12783 |
@@ -16,3 +16,4 @@ testing
|
||||
.coverage_data
|
||||
cover_html
|
||||
test.js
|
||||
.idea
|
||||
|
||||
+2
-1
@@ -1,3 +1,4 @@
|
||||
language: node_js
|
||||
node_js:
|
||||
- 0.6
|
||||
- "0.8"
|
||||
- "0.10"
|
||||
+334
-75
@@ -1,10 +1,269 @@
|
||||
3.4.4 / 2013-10-29
|
||||
==================
|
||||
|
||||
3.0.0beta7 / 2012-07-16
|
||||
* update connect
|
||||
* update supertest
|
||||
* update methods
|
||||
* express(1): replace bodyParser() with urlencoded() and json() #1795 @chirag04
|
||||
|
||||
3.4.3 / 2013-10-23
|
||||
==================
|
||||
|
||||
* update connect
|
||||
|
||||
3.4.2 / 2013-10-18
|
||||
==================
|
||||
|
||||
* update connect
|
||||
* downgrade commander
|
||||
|
||||
3.4.1 / 2013-10-15
|
||||
==================
|
||||
|
||||
* update connect
|
||||
* update commander
|
||||
* jsonp: check if callback is a function
|
||||
* router: wrap encodeURIComponent in a try/catch #1735 (@lxe)
|
||||
* res.format: now includes chraset @1747 (@sorribas)
|
||||
* res.links: allow multiple calls @1746 (@sorribas)
|
||||
|
||||
3.4.0 / 2013-09-07
|
||||
==================
|
||||
|
||||
* add res.vary(). Closes #1682
|
||||
* update connect
|
||||
|
||||
3.3.8 / 2013-09-02
|
||||
==================
|
||||
|
||||
* update connect
|
||||
|
||||
3.3.7 / 2013-08-28
|
||||
==================
|
||||
|
||||
* update connect
|
||||
|
||||
3.3.6 / 2013-08-27
|
||||
==================
|
||||
|
||||
* Revert "remove charset from json responses. Closes #1631" (causes issues in some clients)
|
||||
* add: req.accepts take an argument list
|
||||
|
||||
3.3.4 / 2013-07-08
|
||||
==================
|
||||
|
||||
* update send and connect
|
||||
|
||||
3.3.3 / 2013-07-04
|
||||
==================
|
||||
|
||||
* update connect
|
||||
|
||||
3.3.2 / 2013-07-03
|
||||
==================
|
||||
|
||||
* update connect
|
||||
* update send
|
||||
* remove .version export
|
||||
|
||||
3.3.1 / 2013-06-27
|
||||
==================
|
||||
|
||||
* update connect
|
||||
|
||||
3.3.0 / 2013-06-26
|
||||
==================
|
||||
|
||||
* update connect
|
||||
* add support for multiple X-Forwarded-Proto values. Closes #1646
|
||||
* change: remove charset from json responses. Closes #1631
|
||||
* change: return actual booleans from req.accept* functions
|
||||
* fix jsonp callback array throw
|
||||
|
||||
3.2.6 / 2013-06-02
|
||||
==================
|
||||
|
||||
* update connect
|
||||
|
||||
3.2.5 / 2013-05-21
|
||||
==================
|
||||
|
||||
* update connect
|
||||
* update node-cookie
|
||||
* add: throw a meaningful error when there is no default engine
|
||||
* change generation of ETags with res.send() to GET requests only. Closes #1619
|
||||
|
||||
3.2.4 / 2013-05-09
|
||||
==================
|
||||
|
||||
* fix `req.subdomains` when no Host is present
|
||||
* fix `req.host` when no Host is present, return undefined
|
||||
|
||||
3.2.3 / 2013-05-07
|
||||
==================
|
||||
|
||||
* update connect / qs
|
||||
|
||||
3.2.2 / 2013-05-03
|
||||
==================
|
||||
|
||||
* update qs
|
||||
|
||||
3.2.1 / 2013-04-29
|
||||
==================
|
||||
|
||||
* add app.VERB() paths array deprecation warning
|
||||
* update connect
|
||||
* update qs and remove all ~ semver crap
|
||||
* fix: accept number as value of Signed Cookie
|
||||
|
||||
3.2.0 / 2013-04-15
|
||||
==================
|
||||
|
||||
* add "view" constructor setting to override view behaviour
|
||||
* add req.acceptsEncoding(name)
|
||||
* add req.acceptedEncodings
|
||||
* revert cookie signature change causing session race conditions
|
||||
* fix sorting of Accept values of the same quality
|
||||
|
||||
3.1.2 / 2013-04-12
|
||||
==================
|
||||
|
||||
* add support for custom Accept parameters
|
||||
* update cookie-signature
|
||||
|
||||
3.1.1 / 2013-04-01
|
||||
==================
|
||||
|
||||
* add X-Forwarded-Host support to `req.host`
|
||||
* fix relative redirects
|
||||
* update mkdirp
|
||||
* update buffer-crc32
|
||||
* remove legacy app.configure() method from app template.
|
||||
|
||||
3.1.0 / 2013-01-25
|
||||
==================
|
||||
|
||||
* add support for leading "." in "view engine" setting
|
||||
* add array support to `res.set()`
|
||||
* add node 0.8.x to travis.yml
|
||||
* add "subdomain offset" setting for tweaking `req.subdomains`
|
||||
* add `res.location(url)` implementing `res.redirect()`-like setting of Location
|
||||
* use app.get() for x-powered-by setting for inheritance
|
||||
* fix colons in passwords for `req.auth`
|
||||
|
||||
3.0.6 / 2013-01-04
|
||||
==================
|
||||
|
||||
* add http verb methods to Router
|
||||
* update connect
|
||||
* fix mangling of the `res.cookie()` options object
|
||||
* fix jsonp whitespace escape. Closes #1132
|
||||
|
||||
3.0.5 / 2012-12-19
|
||||
==================
|
||||
|
||||
* add throwing when a non-function is passed to a route
|
||||
* fix: explicitly remove Transfer-Encoding header from 204 and 304 responses
|
||||
* revert "add 'etag' option"
|
||||
|
||||
3.0.4 / 2012-12-05
|
||||
==================
|
||||
|
||||
* add 'etag' option to disable `res.send()` Etags
|
||||
* add escaping of urls in text/plain in `res.redirect()`
|
||||
for old browsers interpreting as html
|
||||
* change crc32 module for a more liberal license
|
||||
* update connect
|
||||
|
||||
3.0.3 / 2012-11-13
|
||||
==================
|
||||
|
||||
* update connect
|
||||
* update cookie module
|
||||
* fix cookie max-age
|
||||
|
||||
3.0.2 / 2012-11-08
|
||||
==================
|
||||
|
||||
* add OPTIONS to cors example. Closes #1398
|
||||
* fix route chaining regression. Closes #1397
|
||||
|
||||
3.0.1 / 2012-11-01
|
||||
==================
|
||||
|
||||
* update connect
|
||||
|
||||
3.0.0 / 2012-10-23
|
||||
==================
|
||||
|
||||
* add `make clean`
|
||||
* add "Basic" check to req.auth
|
||||
* add `req.auth` test coverage
|
||||
* add cb && cb(payload) to `res.jsonp()`. Closes #1374
|
||||
* add backwards compat for `res.redirect()` status. Closes #1336
|
||||
* add support for `res.json()` to retain previously defined Content-Types. Closes #1349
|
||||
* update connect
|
||||
* change `res.redirect()` to utilize a pathname-relative Location again. Closes #1382
|
||||
* remove non-primitive string support for `res.send()`
|
||||
* fix view-locals example. Closes #1370
|
||||
* fix route-separation example
|
||||
|
||||
3.0.0rc5 / 2012-09-18
|
||||
==================
|
||||
|
||||
* update connect
|
||||
* add redis search example
|
||||
* add static-files example
|
||||
* add "x-powered-by" setting (`app.disable('x-powered-by')`)
|
||||
* add "application/octet-stream" redirect Accept test case. Closes #1317
|
||||
|
||||
3.0.0rc4 / 2012-08-30
|
||||
==================
|
||||
|
||||
* add `res.jsonp()`. Closes #1307
|
||||
* add "verbose errors" option to error-pages example
|
||||
* add another route example to express(1) so people are not so confused
|
||||
* add redis online user activity tracking example
|
||||
* update connect dep
|
||||
* fix etag quoting. Closes #1310
|
||||
* fix error-pages 404 status
|
||||
* fix jsonp callback char restrictions
|
||||
* remove old OPTIONS default response
|
||||
|
||||
3.0.0rc3 / 2012-08-13
|
||||
==================
|
||||
|
||||
* update connect dep
|
||||
* fix signed cookies to work with `connect.cookieParser()` ("s:" prefix was missing) [tnydwrds]
|
||||
* fix `res.render()` clobbering of "locals"
|
||||
|
||||
3.0.0rc2 / 2012-08-03
|
||||
==================
|
||||
|
||||
* add CORS example
|
||||
* update connect dep
|
||||
* deprecate `.createServer()` & remove old stale examples
|
||||
* fix: escape `res.redirect()` link
|
||||
* fix vhost example
|
||||
|
||||
3.0.0rc1 / 2012-07-24
|
||||
==================
|
||||
|
||||
* add more examples to view-locals
|
||||
* add scheme-relative redirects (`res.redirect("//foo.com")`) support
|
||||
* update cookie dep
|
||||
* update connect dep
|
||||
* update send dep
|
||||
* fix `express(1)` -h flag, use -H for hogan. Closes #1245
|
||||
* fix `res.sendfile()` socket error handling regression
|
||||
|
||||
3.0.0beta7 / 2012-07-16
|
||||
==================
|
||||
|
||||
* update connect dep for `send()` root normalization regression
|
||||
|
||||
3.0.0beta6 / 2012-07-13
|
||||
3.0.0beta6 / 2012-07-13
|
||||
==================
|
||||
|
||||
* add `err.view` property for view errors. Closes #1226
|
||||
@@ -14,7 +273,7 @@
|
||||
* change `res.send` to use "response-send" module
|
||||
* remove `app.locals.use` and `res.locals.use`, use regular middleware
|
||||
|
||||
3.0.0beta5 / 2012-07-03
|
||||
3.0.0beta5 / 2012-07-03
|
||||
==================
|
||||
|
||||
* add "make check" support
|
||||
@@ -25,7 +284,7 @@
|
||||
* update auth example to utilize cores pbkdf2
|
||||
* updated tests to use "supertest"
|
||||
|
||||
3.0.0beta4 / 2012-06-25
|
||||
3.0.0beta4 / 2012-06-25
|
||||
==================
|
||||
|
||||
* Added `req.auth`
|
||||
@@ -37,7 +296,7 @@
|
||||
* Revert "Added + support to the router"
|
||||
* Fixed `res.send()` freshness check, respect res.statusCode
|
||||
|
||||
3.0.0beta3 / 2012-06-15
|
||||
3.0.0beta3 / 2012-06-15
|
||||
==================
|
||||
|
||||
* Added hogan `--hjs` to express(1) [nullfirm]
|
||||
@@ -46,7 +305,7 @@
|
||||
* Changed: `res.send()` always checks freshness
|
||||
* Fixed: expose connects mime module. Cloases #1165
|
||||
|
||||
3.0.0beta2 / 2012-06-06
|
||||
3.0.0beta2 / 2012-06-06
|
||||
==================
|
||||
|
||||
* Added `+` support to the router
|
||||
@@ -54,13 +313,13 @@
|
||||
* Changed `req.param()` to check route first
|
||||
* Update connect dep
|
||||
|
||||
3.0.0beta1 / 2012-06-01
|
||||
3.0.0beta1 / 2012-06-01
|
||||
==================
|
||||
|
||||
* Added `res.format()` callback to override default 406 behaviour
|
||||
* Fixed `res.redirect()` 406. Closes #1154
|
||||
|
||||
3.0.0alpha5 / 2012-05-30
|
||||
3.0.0alpha5 / 2012-05-30
|
||||
==================
|
||||
|
||||
* Added `req.ip`
|
||||
@@ -69,14 +328,14 @@
|
||||
* Changed: dont reverse `req.ips`
|
||||
* Fixed "trust proxy" setting check for `req.ips`
|
||||
|
||||
3.0.0alpha4 / 2012-05-09
|
||||
3.0.0alpha4 / 2012-05-09
|
||||
==================
|
||||
|
||||
* Added: allow `[]` in jsonp callback. Closes #1128
|
||||
* Added `PORT` env var support in generated template. Closes #1118 [benatkin]
|
||||
* Updated: connect 2.2.2
|
||||
|
||||
3.0.0alpha3 / 2012-05-04
|
||||
3.0.0alpha3 / 2012-05-04
|
||||
==================
|
||||
|
||||
* Added public `app.routes`. Closes #887
|
||||
@@ -91,7 +350,7 @@
|
||||
* Changed: `make test` now runs unit / acceptance tests
|
||||
* Fixed req/res proto inheritance
|
||||
|
||||
3.0.0alpha2 / 2012-04-26
|
||||
3.0.0alpha2 / 2012-04-26
|
||||
==================
|
||||
|
||||
* Added `make benchmark` back
|
||||
@@ -107,7 +366,7 @@
|
||||
* Fixed session example. Closes #1105
|
||||
* Fixed generated express dep. Closes #1078
|
||||
|
||||
3.0.0alpha1 / 2012-04-15
|
||||
3.0.0alpha1 / 2012-04-15
|
||||
==================
|
||||
|
||||
* Added `app.locals.use(callback)`
|
||||
@@ -162,54 +421,54 @@
|
||||
* Fixed `res.sendfile()` with non-GET. Closes #723
|
||||
* Fixed express(1) public dir for windows. Closes #866
|
||||
|
||||
2.5.9/ 2012-04-02
|
||||
2.5.9/ 2012-04-02
|
||||
==================
|
||||
|
||||
* Added support for PURGE request method [pbuyle]
|
||||
* Fixed `express(1)` generated app `app.address()` before `listening` [mmalecki]
|
||||
|
||||
2.5.8 / 2012-02-08
|
||||
2.5.8 / 2012-02-08
|
||||
==================
|
||||
|
||||
* Update mkdirp dep. Closes #991
|
||||
|
||||
2.5.7 / 2012-02-06
|
||||
2.5.7 / 2012-02-06
|
||||
==================
|
||||
|
||||
* Fixed `app.all` duplicate DELETE requests [mscdex]
|
||||
|
||||
2.5.6 / 2012-01-13
|
||||
2.5.6 / 2012-01-13
|
||||
==================
|
||||
|
||||
* Updated hamljs dev dep. Closes #953
|
||||
|
||||
2.5.5 / 2012-01-08
|
||||
2.5.5 / 2012-01-08
|
||||
==================
|
||||
|
||||
* Fixed: set `filename` on cached templates [matthewleon]
|
||||
|
||||
2.5.4 / 2012-01-02
|
||||
2.5.4 / 2012-01-02
|
||||
==================
|
||||
|
||||
* Fixed `express(1)` eol on 0.4.x. Closes #947
|
||||
|
||||
2.5.3 / 2011-12-30
|
||||
2.5.3 / 2011-12-30
|
||||
==================
|
||||
|
||||
* Fixed `req.is()` when a charset is present
|
||||
|
||||
2.5.2 / 2011-12-10
|
||||
2.5.2 / 2011-12-10
|
||||
==================
|
||||
|
||||
* Fixed: express(1) LF -> CRLF for windows
|
||||
|
||||
2.5.1 / 2011-11-17
|
||||
2.5.1 / 2011-11-17
|
||||
==================
|
||||
|
||||
* Changed: updated connect to 1.8.x
|
||||
* Removed sass.js support from express(1)
|
||||
|
||||
2.5.0 / 2011-10-24
|
||||
2.5.0 / 2011-10-24
|
||||
==================
|
||||
|
||||
* Added ./routes dir for generated app by default
|
||||
@@ -218,7 +477,7 @@
|
||||
* Removed `make test-cov` since it wont work with node 0.5.x
|
||||
* Fixed express(1) public dir for windows. Closes #866
|
||||
|
||||
2.4.7 / 2011-10-05
|
||||
2.4.7 / 2011-10-05
|
||||
==================
|
||||
|
||||
* Added mkdirp to express(1). Closes #795
|
||||
@@ -229,17 +488,17 @@
|
||||
* Fixed `req.flash()`, only escape args
|
||||
* Fixed absolute path checking on windows. Closes #829 [reported by andrewpmckenzie]
|
||||
|
||||
2.4.6 / 2011-08-22
|
||||
2.4.6 / 2011-08-22
|
||||
==================
|
||||
|
||||
* Fixed multiple param callback regression. Closes #824 [reported by TroyGoode]
|
||||
|
||||
2.4.5 / 2011-08-19
|
||||
2.4.5 / 2011-08-19
|
||||
==================
|
||||
|
||||
* Added support for routes to handle errors. Closes #809
|
||||
* Added `app.routes.all()`. Closes #803
|
||||
* Added "basepath" setting to work in conjunction with reverse proxies etc.
|
||||
* Added "basepath" setting to work in conjunction with reverse proxies etc.
|
||||
* Refactored `Route` to use a single array of callbacks
|
||||
* Added support for multiple callbacks for `app.param()`. Closes #801
|
||||
Closes #805
|
||||
@@ -247,25 +506,25 @@ Closes #805
|
||||
* Dependency: `qs >= 0.3.1`
|
||||
* Fixed `res.redirect()` on windows due to `join()` usage. Closes #808
|
||||
|
||||
2.4.4 / 2011-08-05
|
||||
2.4.4 / 2011-08-05
|
||||
==================
|
||||
|
||||
* Fixed `res.header()` intention of a set, even when `undefined`
|
||||
* Fixed `*`, value no longer required
|
||||
* Fixed `res.send(204)` support. Closes #771
|
||||
|
||||
2.4.3 / 2011-07-14
|
||||
2.4.3 / 2011-07-14
|
||||
==================
|
||||
|
||||
* Added docs for `status` option special-case. Closes #739
|
||||
* Fixed `options.filename`, exposing the view path to template engines
|
||||
|
||||
2.4.2. / 2011-07-06
|
||||
2.4.2. / 2011-07-06
|
||||
==================
|
||||
|
||||
* Revert "removed jsonp stripping" for XSS
|
||||
|
||||
2.4.1 / 2011-07-06
|
||||
2.4.1 / 2011-07-06
|
||||
==================
|
||||
|
||||
* Added `res.json()` JSONP support. Closes #737
|
||||
@@ -277,14 +536,14 @@ Closes #805
|
||||
* Changed; default cookie path to "home" setting. Closes #731
|
||||
* Removed _pids/logs_ creation from express(1)
|
||||
|
||||
2.4.0 / 2011-06-28
|
||||
2.4.0 / 2011-06-28
|
||||
==================
|
||||
|
||||
* Added chainable `res.status(code)`
|
||||
* Added `res.json()`, an explicit version of `res.send(obj)`
|
||||
* Added simple web-service example
|
||||
|
||||
2.3.12 / 2011-06-22
|
||||
2.3.12 / 2011-06-22
|
||||
==================
|
||||
|
||||
* \#express is now on freenode! come join!
|
||||
@@ -296,7 +555,7 @@ Closes #805
|
||||
* Fixed view layout bug. Closes #720
|
||||
* Fixed; ignore body on 304. Closes #701
|
||||
|
||||
2.3.11 / 2011-06-04
|
||||
2.3.11 / 2011-06-04
|
||||
==================
|
||||
|
||||
* Added `npm test`
|
||||
@@ -304,14 +563,14 @@ Closes #805
|
||||
* Fixed; `express(1)` adds express as a dep
|
||||
* Fixed; prune on `prepublish`
|
||||
|
||||
2.3.10 / 2011-05-27
|
||||
2.3.10 / 2011-05-27
|
||||
==================
|
||||
|
||||
* Added `req.route`, exposing the current route
|
||||
* Added _package.json_ generation support to `express(1)`
|
||||
* Fixed call to `app.param()` function for optional params. Closes #682
|
||||
|
||||
2.3.9 / 2011-05-25
|
||||
2.3.9 / 2011-05-25
|
||||
==================
|
||||
|
||||
* Fixed bug-ish with `../' in `res.partial()` calls
|
||||
@@ -330,7 +589,7 @@ Closes #805
|
||||
* Removed module.parent check from express(1) generated app. Closes #670
|
||||
* Refactored router. Closes #639
|
||||
|
||||
2.3.6 / 2011-05-20
|
||||
2.3.6 / 2011-05-20
|
||||
==================
|
||||
|
||||
* Changed; using devDependencies instead of git submodules
|
||||
@@ -338,30 +597,30 @@ Closes #805
|
||||
* Fixed markdown example
|
||||
* Fixed view caching, should not be enabled in development
|
||||
|
||||
2.3.5 / 2011-05-20
|
||||
2.3.5 / 2011-05-20
|
||||
==================
|
||||
|
||||
* Added export `.view` as alias for `.View`
|
||||
|
||||
2.3.4 / 2011-05-08
|
||||
2.3.4 / 2011-05-08
|
||||
==================
|
||||
|
||||
* Added `./examples/say`
|
||||
* Fixed `res.sendfile()` bug preventing the transfer of files with spaces
|
||||
|
||||
2.3.3 / 2011-05-03
|
||||
2.3.3 / 2011-05-03
|
||||
==================
|
||||
|
||||
* Added "case sensitive routes" option.
|
||||
* Changed; split methods supported per rfc [slaskis]
|
||||
* Fixed route-specific middleware when using the same callback function several times
|
||||
|
||||
2.3.2 / 2011-04-27
|
||||
2.3.2 / 2011-04-27
|
||||
==================
|
||||
|
||||
* Fixed view hints
|
||||
|
||||
2.3.1 / 2011-04-26
|
||||
2.3.1 / 2011-04-26
|
||||
==================
|
||||
|
||||
* Added `app.match()` as `app.match.all()`
|
||||
@@ -371,7 +630,7 @@ Closes #805
|
||||
* Fixed template caching collision issue. Closes #644
|
||||
* Moved router over from connect and started refactor
|
||||
|
||||
2.3.0 / 2011-04-25
|
||||
2.3.0 / 2011-04-25
|
||||
==================
|
||||
|
||||
* Added options support to `res.clearCookie()`
|
||||
@@ -380,18 +639,18 @@ Closes #805
|
||||
* Changed; auto set Content-Type in res.attachement [Aaron Heckmann]
|
||||
* Renamed "cache views" to "view cache". Closes #628
|
||||
* Fixed caching of views when using several apps. Closes #637
|
||||
* Fixed gotcha invoking `app.param()` callbacks once per route middleware.
|
||||
* Fixed gotcha invoking `app.param()` callbacks once per route middleware.
|
||||
Closes #638
|
||||
* Fixed partial lookup precedence. Closes #631
|
||||
Shaw]
|
||||
|
||||
2.2.2 / 2011-04-12
|
||||
2.2.2 / 2011-04-12
|
||||
==================
|
||||
|
||||
* Added second callback support for `res.download()` connection errors
|
||||
* Fixed `filename` option passing to template engine
|
||||
|
||||
2.2.1 / 2011-04-04
|
||||
2.2.1 / 2011-04-04
|
||||
==================
|
||||
|
||||
* Added `layout(path)` helper to change the layout within a view. Closes #610
|
||||
@@ -405,7 +664,7 @@ Shaw]
|
||||
* Removed `request` and `response` locals
|
||||
* Changed; errorHandler page title is now `Express` instead of `Connect`
|
||||
|
||||
2.2.0 / 2011-03-30
|
||||
2.2.0 / 2011-03-30
|
||||
==================
|
||||
|
||||
* Added `app.lookup.VERB()`, ex `app.lookup.put('/user/:id')`. Closes #606
|
||||
@@ -413,14 +672,14 @@ Shaw]
|
||||
* Added `app.VERB(path)` as alias of `app.lookup.VERB()`.
|
||||
* Dependency `connect >= 1.2.0`
|
||||
|
||||
2.1.1 / 2011-03-29
|
||||
2.1.1 / 2011-03-29
|
||||
==================
|
||||
|
||||
* Added; expose `err.view` object when failing to locate a view
|
||||
* Fixed `res.partial()` call `next(err)` when no callback is given [reported by aheckmann]
|
||||
* Fixed; `res.send(undefined)` responds with 204 [aheckmann]
|
||||
|
||||
2.1.0 / 2011-03-24
|
||||
2.1.0 / 2011-03-24
|
||||
==================
|
||||
|
||||
* Added `<root>/_?<name>` partial lookup support. Closes #447
|
||||
@@ -431,20 +690,20 @@ Shaw]
|
||||
* Fixed stylus example for latest version
|
||||
* Fixed; wrap try/catch around `res.render()`
|
||||
|
||||
2.0.0 / 2011-03-17
|
||||
2.0.0 / 2011-03-17
|
||||
==================
|
||||
|
||||
* Fixed up index view path alternative.
|
||||
* Changed; `res.locals()` without object returns the locals
|
||||
|
||||
2.0.0rc3 / 2011-03-17
|
||||
2.0.0rc3 / 2011-03-17
|
||||
==================
|
||||
|
||||
* Added `res.locals(obj)` to compliment `res.local(key, val)`
|
||||
* Added `res.partial()` callback support
|
||||
* Fixed recursive error reporting issue in `res.render()`
|
||||
|
||||
2.0.0rc2 / 2011-03-17
|
||||
2.0.0rc2 / 2011-03-17
|
||||
==================
|
||||
|
||||
* Changed; `partial()` "locals" are now optional
|
||||
@@ -453,14 +712,14 @@ Shaw]
|
||||
* Fixed blog example
|
||||
* Fixed `{req,res}.app` reference when mounting [Ben Weaver]
|
||||
|
||||
2.0.0rc / 2011-03-14
|
||||
2.0.0rc / 2011-03-14
|
||||
==================
|
||||
|
||||
* Fixed; expose `HTTPSServer` constructor
|
||||
* Fixed express(1) default test charset. Closes #579 [reported by secoif]
|
||||
* Fixed; default charset to utf-8 instead of utf8 for lame IE [reported by NickP]
|
||||
|
||||
2.0.0beta3 / 2011-03-09
|
||||
2.0.0beta3 / 2011-03-09
|
||||
==================
|
||||
|
||||
* Added support for `res.contentType()` literal
|
||||
@@ -478,13 +737,13 @@ Shaw]
|
||||
* Fixed; default `res.send()` string charset to utf8
|
||||
* Removed `Partial` constructor (not currently used)
|
||||
|
||||
2.0.0beta2 / 2011-03-07
|
||||
2.0.0beta2 / 2011-03-07
|
||||
==================
|
||||
|
||||
* Added res.render() `.locals` support back to aid in migration process
|
||||
* Fixed flash example
|
||||
|
||||
2.0.0beta / 2011-03-03
|
||||
2.0.0beta / 2011-03-03
|
||||
==================
|
||||
|
||||
* Added HTTPS support
|
||||
@@ -517,46 +776,46 @@ Shaw]
|
||||
* Fixed; strip unsafe chars from jsonp callbacks
|
||||
* Removed "stream threshold" setting
|
||||
|
||||
1.0.8 / 2011-03-01
|
||||
1.0.8 / 2011-03-01
|
||||
==================
|
||||
|
||||
* Allow `req.query` to be pre-defined (via middleware or other parent app)
|
||||
* "connect": ">= 0.5.0 < 1.0.0". Closes #547
|
||||
* Removed the long deprecated __EXPRESS_ENV__ support
|
||||
|
||||
1.0.7 / 2011-02-07
|
||||
1.0.7 / 2011-02-07
|
||||
==================
|
||||
|
||||
* Fixed `render()` setting inheritance.
|
||||
Mounted apps would not inherit "view engine"
|
||||
|
||||
1.0.6 / 2011-02-07
|
||||
1.0.6 / 2011-02-07
|
||||
==================
|
||||
|
||||
* Fixed `view engine` setting bug when period is in dirname
|
||||
|
||||
1.0.5 / 2011-02-05
|
||||
1.0.5 / 2011-02-05
|
||||
==================
|
||||
|
||||
* Added secret to generated app `session()` call
|
||||
|
||||
1.0.4 / 2011-02-05
|
||||
1.0.4 / 2011-02-05
|
||||
==================
|
||||
|
||||
* Added `qs` dependency to _package.json_
|
||||
* Fixed namespaced `require()`s for latest connect support
|
||||
|
||||
1.0.3 / 2011-01-13
|
||||
1.0.3 / 2011-01-13
|
||||
==================
|
||||
|
||||
* Remove unsafe characters from JSONP callback names [Ryan Grove]
|
||||
|
||||
1.0.2 / 2011-01-10
|
||||
1.0.2 / 2011-01-10
|
||||
==================
|
||||
|
||||
* Removed nested require, using `connect.router`
|
||||
|
||||
1.0.1 / 2010-12-29
|
||||
1.0.1 / 2010-12-29
|
||||
==================
|
||||
|
||||
* Fixed for middleware stacked via `createServer()`
|
||||
@@ -564,7 +823,7 @@ Shaw]
|
||||
would not have access to Express methods such as `res.send()`
|
||||
or props like `req.query` etc.
|
||||
|
||||
1.0.0 / 2010-11-16
|
||||
1.0.0 / 2010-11-16
|
||||
==================
|
||||
|
||||
* Added; deduce partial object names from the last segment.
|
||||
@@ -578,7 +837,7 @@ Shaw]
|
||||
* Added _-s, --session[s]_ flag to express(1) to add session related middleware
|
||||
* Added _--template_ flag to express(1) to specify the
|
||||
template engine to use.
|
||||
* Added _--css_ flag to express(1) to specify the
|
||||
* Added _--css_ flag to express(1) to specify the
|
||||
stylesheet engine to use (or just plain css by default).
|
||||
* Added `app.all()` support [thanks aheckmann]
|
||||
* Added partial direct object support.
|
||||
@@ -591,7 +850,7 @@ Shaw]
|
||||
* Fixed partial local inheritance precedence. [reported by Nick Poulden] Closes #454
|
||||
* Fixed jsonp support; _text/javascript_ as per mailinglist discussion
|
||||
|
||||
1.0.0rc4 / 2010-10-14
|
||||
1.0.0rc4 / 2010-10-14
|
||||
==================
|
||||
|
||||
* Added _NODE_ENV_ support, _EXPRESS_ENV_ is deprecated and will be removed in 1.0.0
|
||||
@@ -610,7 +869,7 @@ Shaw]
|
||||
* Fixed; exposing _./support_ libs to examples so they can run without installs
|
||||
* Fixed mvc example
|
||||
|
||||
1.0.0rc3 / 2010-09-20
|
||||
1.0.0rc3 / 2010-09-20
|
||||
==================
|
||||
|
||||
* Added confirmation for `express(1)` app generation. Closes #391
|
||||
@@ -633,7 +892,7 @@ Shaw]
|
||||
* Fixed bug messing with error handlers when `listenFD()` is called instead of `listen()`. [thanks guillermo]
|
||||
|
||||
|
||||
1.0.0rc2 / 2010-08-17
|
||||
1.0.0rc2 / 2010-08-17
|
||||
==================
|
||||
|
||||
* Added `app.register()` for template engine mapping. Closes #390
|
||||
@@ -646,7 +905,7 @@ Shaw]
|
||||
* Fixed `res.sendfile()` error handling, defer via `next()`
|
||||
* Fixed `res.render()` callback when a layout is used [thanks guillermo]
|
||||
* Fixed; `make install` creating ~/.node_libraries when not present
|
||||
* Fixed issue preventing error handlers from being defined anywhere. Closes #387
|
||||
* Fixed issue preventing error handlers from being defined anywhere. Closes #387
|
||||
|
||||
1.0.0rc / 2010-07-28
|
||||
==================
|
||||
@@ -664,7 +923,7 @@ Shaw]
|
||||
* Fixed "home" setting
|
||||
* Fixed middleware/router precedence issue. Closes #366
|
||||
* Fixed; _configure()_ callbacks called immediately. Closes #368
|
||||
|
||||
|
||||
1.0.0beta2 / 2010-07-23
|
||||
==================
|
||||
|
||||
@@ -799,7 +1058,7 @@ Shaw]
|
||||
* Updated dependencies
|
||||
* Removed set("session cookie") in favour of use(Session, { cookie: { ... }})
|
||||
* Removed utils.mixin(); use Object#mergeDeep()
|
||||
|
||||
|
||||
0.8.0 / 2010-03-19
|
||||
==================
|
||||
|
||||
@@ -866,16 +1125,16 @@ Shaw]
|
||||
|
||||
* Added seed.yml for kiwi package management support
|
||||
* Added HTTP client query string support when method is GET. Closes #205
|
||||
|
||||
|
||||
* Added support for arbitrary view engines.
|
||||
For example "foo.engine.html" will now require('engine'),
|
||||
the exports from this module are cached after the first require().
|
||||
|
||||
|
||||
* Added async plugin support
|
||||
|
||||
|
||||
* Removed usage of RESTful route funcs as http client
|
||||
get() etc, use http.get() and friends
|
||||
|
||||
|
||||
* Removed custom exceptions
|
||||
|
||||
0.5.0 / 2010-03-10
|
||||
|
||||
+1
-1
@@ -1,6 +1,6 @@
|
||||
(The MIT License)
|
||||
|
||||
Copyright (c) 2009-2011 TJ Holowaychuk <tj@vision-media.ca>
|
||||
Copyright (c) 2009-2013 TJ Holowaychuk <tj@vision-media.ca>
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining
|
||||
a copy of this software and associated documentation files (the
|
||||
|
||||
+7
-14
@@ -1,16 +1,7 @@
|
||||
|
||||
MOCHA_OPTS=
|
||||
MOCHA_OPTS= --check-leaks
|
||||
REPORTER = dot
|
||||
|
||||
docs: docs/express.md
|
||||
|
||||
docs/express.md: docs/application.md docs/request.md docs/response.md
|
||||
cat $^ > $@
|
||||
|
||||
docs/%.md: lib/%.js
|
||||
@mkdir -p docs
|
||||
dox --raw < $< | ./support/docs > $@
|
||||
|
||||
check: test
|
||||
|
||||
test: test-unit test-acceptance
|
||||
@@ -18,6 +9,7 @@ test: test-unit test-acceptance
|
||||
test-unit:
|
||||
@NODE_ENV=test ./node_modules/.bin/mocha \
|
||||
--reporter $(REPORTER) \
|
||||
--globals setImmediate,clearImmediate \
|
||||
$(MOCHA_OPTS)
|
||||
|
||||
test-acceptance:
|
||||
@@ -32,10 +24,11 @@ test-cov: lib-cov
|
||||
lib-cov:
|
||||
@jscoverage lib lib-cov
|
||||
|
||||
docclean:
|
||||
rm -fr docs
|
||||
|
||||
benchmark:
|
||||
@./support/bench
|
||||
|
||||
.PHONY: docs docclean test test-unit test-acceptance benchmark
|
||||
clean:
|
||||
rm -f coverage.html
|
||||
rm -fr lib-cov
|
||||
|
||||
.PHONY: test test-unit test-acceptance benchmark clean
|
||||
|
||||
+15
-72
@@ -1,7 +1,8 @@
|
||||
[](http://expressjs.com/)
|
||||
|
||||

|
||||
Fast, unopinionated, minimalist web framework for [node](http://nodejs.org).
|
||||
|
||||
Fast, unopinionated, minimalist web framework for [node](http://nodejs.org). [](http://travis-ci.org/visionmedia/express)
|
||||
[](http://travis-ci.org/visionmedia/express) [](https://www.gittip.com/visionmedia/)
|
||||
|
||||
```js
|
||||
var express = require('express');
|
||||
@@ -18,10 +19,6 @@ app.listen(3000);
|
||||
|
||||
$ npm install -g express
|
||||
|
||||
To install the 3.0 alpha:
|
||||
|
||||
$ npm install -g express@3.0
|
||||
|
||||
## Quick Start
|
||||
|
||||
The quickest way to get started with express is to utilize the executable `express(1)` to generate an application as shown below:
|
||||
@@ -56,7 +53,7 @@ app.listen(3000);
|
||||
The Express philosophy is to provide small, robust tooling for HTTP servers. Making
|
||||
it a great solution for single page applications, web sites, hybrids, or public
|
||||
HTTP APIs.
|
||||
|
||||
|
||||
Built on Connect you can use _only_ what you need, and nothing more, applications
|
||||
can be as big or as small as you like, even a single file. Express does
|
||||
not force you to use any specific ORM or template engine. With support for over
|
||||
@@ -65,17 +62,19 @@ app.listen(3000);
|
||||
|
||||
## More Information
|
||||
|
||||
* [Website and Documentation](http://expressjs.com/) stored at [visionmedia/expressjs.com](https://github.com/visionmedia/expressjs.com)
|
||||
* Join #express on freenode
|
||||
* [Google Group](http://groups.google.com/group/express-js) for discussion
|
||||
* Follow [tjholowaychuk](http://twitter.com/tjholowaychuk) on twitter for updates
|
||||
* Visit the [Wiki](http://github.com/visionmedia/express/wiki)
|
||||
* [日本語ドキュメンテーション](http://hideyukisaito.com/doc/expressjs/) by [hideyukisaito](https://github.com/hideyukisaito)
|
||||
* [Русскоязычная документация](http://express-js.ru/)
|
||||
* [Русскоязычная документация](http://jsman.ru/express/)
|
||||
* Run express examples [online](https://runnable.com/express)
|
||||
|
||||
## Viewing Examples
|
||||
|
||||
First install the dev dependencies to install all the example / test suite deps:
|
||||
Clone the Express repo, then install the dev dependencies to install all the example / test suite deps:
|
||||
|
||||
$ git clone git://github.com/visionmedia/express.git --depth 1
|
||||
$ cd express
|
||||
$ npm install
|
||||
|
||||
@@ -83,6 +82,10 @@ then run whichever tests you want:
|
||||
|
||||
$ node examples/content-negotiation
|
||||
|
||||
You can also view live examples here
|
||||
|
||||
<a href="https://runnable.com/express" target="_blank"><img src="https://runnable.com/external/styles/assets/runnablebtn.png" style="width:67px;height:25px;"></a>
|
||||
|
||||
## Running Tests
|
||||
|
||||
To run the test suite first invoke the following command within the repo, installing the development dependencies:
|
||||
@@ -95,69 +98,9 @@ then run the tests:
|
||||
|
||||
## Contributors
|
||||
|
||||
```
|
||||
project: express
|
||||
commits: 3559
|
||||
active : 468 days
|
||||
files : 237
|
||||
authors:
|
||||
1891 Tj Holowaychuk 53.1%
|
||||
1285 visionmedia 36.1%
|
||||
182 TJ Holowaychuk 5.1%
|
||||
54 Aaron Heckmann 1.5%
|
||||
34 csausdev 1.0%
|
||||
26 ciaranj 0.7%
|
||||
21 Robert Sköld 0.6%
|
||||
6 Guillermo Rauch 0.2%
|
||||
3 Dav Glass 0.1%
|
||||
3 Nick Poulden 0.1%
|
||||
2 Randy Merrill 0.1%
|
||||
2 Benny Wong 0.1%
|
||||
2 Hunter Loftis 0.1%
|
||||
2 Jake Gordon 0.1%
|
||||
2 Brian McKinney 0.1%
|
||||
2 Roman Shtylman 0.1%
|
||||
2 Ben Weaver 0.1%
|
||||
2 Dave Hoover 0.1%
|
||||
2 Eivind Fjeldstad 0.1%
|
||||
2 Daniel Shaw 0.1%
|
||||
1 Matt Colyer 0.0%
|
||||
1 Pau Ramon 0.0%
|
||||
1 Pero Pejovic 0.0%
|
||||
1 Peter Rekdal Sunde 0.0%
|
||||
1 Raynos 0.0%
|
||||
1 Teng Siong Ong 0.0%
|
||||
1 Viktor Kelemen 0.0%
|
||||
1 ctide 0.0%
|
||||
1 8bitDesigner 0.0%
|
||||
1 isaacs 0.0%
|
||||
1 mgutz 0.0%
|
||||
1 pikeas 0.0%
|
||||
1 shuwatto 0.0%
|
||||
1 tstrimple 0.0%
|
||||
1 ewoudj 0.0%
|
||||
1 Adam Sanderson 0.0%
|
||||
1 Andrii Kostenko 0.0%
|
||||
1 Andy Hiew 0.0%
|
||||
1 Arpad Borsos 0.0%
|
||||
1 Ashwin Purohit 0.0%
|
||||
1 Benjen 0.0%
|
||||
1 Darren Torpey 0.0%
|
||||
1 Greg Ritter 0.0%
|
||||
1 Gregory Ritter 0.0%
|
||||
1 James Herdman 0.0%
|
||||
1 Jim Snodgrass 0.0%
|
||||
1 Joe McCann 0.0%
|
||||
1 Jonathan Dumaine 0.0%
|
||||
1 Jonathan Palardy 0.0%
|
||||
1 Jonathan Zacsh 0.0%
|
||||
1 Justin Lilly 0.0%
|
||||
1 Ken Sato 0.0%
|
||||
1 Maciej Małecki 0.0%
|
||||
1 Masahiro Hayashi 0.0%
|
||||
```
|
||||
https://github.com/visionmedia/express/graphs/contributors
|
||||
|
||||
## License
|
||||
## License
|
||||
|
||||
(The MIT License)
|
||||
|
||||
|
||||
+45
-25
@@ -4,8 +4,7 @@
|
||||
* Module dependencies.
|
||||
*/
|
||||
|
||||
var exec = require('child_process').exec
|
||||
, program = require('commander')
|
||||
var program = require('commander')
|
||||
, mkdirp = require('mkdirp')
|
||||
, pkg = require('../package.json')
|
||||
, version = pkg.version
|
||||
@@ -16,10 +15,11 @@ var exec = require('child_process').exec
|
||||
|
||||
program
|
||||
.version(version)
|
||||
.usage('[options] [dir]')
|
||||
.option('-s, --sessions', 'add session support')
|
||||
.option('-e, --ejs', 'add ejs engine support (defaults to jade)')
|
||||
.option('-J, --jshtml', 'add jshtml engine support (defaults to jade)')
|
||||
.option('-h, --hogan', 'add hogan.js engine support')
|
||||
.option('-H, --hogan', 'add hogan.js engine support')
|
||||
.option('-c, --css <engine>', 'add stylesheet <engine> support (less|stylus) (defaults to plain css)')
|
||||
.option('-f, --force', 'force on non-empty directory')
|
||||
.parse(process.argv);
|
||||
@@ -30,7 +30,7 @@ var path = program.args.shift() || '.';
|
||||
|
||||
// end-of-line code
|
||||
|
||||
var eol = 'win32' == os.platform() ? '\r\n' : '\n'
|
||||
var eol = os.EOL
|
||||
|
||||
// Template engine
|
||||
|
||||
@@ -54,6 +54,21 @@ var index = [
|
||||
, '};'
|
||||
].join(eol);
|
||||
|
||||
/**
|
||||
* Routes users template.
|
||||
*/
|
||||
|
||||
var users = [
|
||||
''
|
||||
, '/*'
|
||||
, ' * GET users listing.'
|
||||
, ' */'
|
||||
, ''
|
||||
, 'exports.list = function(req, res){'
|
||||
, ' res.send("respond with a resource");'
|
||||
, '};'
|
||||
].join(eol);
|
||||
|
||||
/**
|
||||
* Jade layout template.
|
||||
*/
|
||||
@@ -193,32 +208,36 @@ var app = [
|
||||
, ' * Module dependencies.'
|
||||
, ' */'
|
||||
, ''
|
||||
, 'var express = require(\'express\')'
|
||||
, ' , routes = require(\'./routes\')'
|
||||
, ' , http = require(\'http\');'
|
||||
, 'var express = require(\'express\');'
|
||||
, 'var routes = require(\'./routes\');'
|
||||
, 'var user = require(\'./routes/user\');'
|
||||
, 'var http = require(\'http\');'
|
||||
, 'var path = require(\'path\');'
|
||||
, ''
|
||||
, 'var app = express();'
|
||||
, ''
|
||||
, 'app.configure(function(){'
|
||||
, ' app.set(\'port\', process.env.PORT || 3000);'
|
||||
, ' app.set(\'views\', __dirname + \'/views\');'
|
||||
, ' app.set(\'view engine\', \':TEMPLATE\');'
|
||||
, ' app.use(express.favicon());'
|
||||
, ' app.use(express.logger(\'dev\'));'
|
||||
, ' app.use(express.bodyParser());'
|
||||
, ' app.use(express.methodOverride());{sess}'
|
||||
, ' app.use(app.router);{css}'
|
||||
, ' app.use(express.static(__dirname + \'/public\'));'
|
||||
, '});'
|
||||
, '// all environments'
|
||||
, 'app.set(\'port\', process.env.PORT || 3000);'
|
||||
, 'app.set(\'views\', path.join(__dirname, \'views\'));'
|
||||
, 'app.set(\'view engine\', \':TEMPLATE\');'
|
||||
, 'app.use(express.favicon());'
|
||||
, 'app.use(express.logger(\'dev\'));'
|
||||
, 'app.use(express.json());'
|
||||
, 'app.use(express.urlencoded());'
|
||||
, 'app.use(express.methodOverride());{sess}'
|
||||
, 'app.use(app.router);{css}'
|
||||
, 'app.use(express.static(path.join(__dirname, \'public\')));'
|
||||
, ''
|
||||
, 'app.configure(\'development\', function(){'
|
||||
, '// development only'
|
||||
, 'if (\'development\' == app.get(\'env\')) {'
|
||||
, ' app.use(express.errorHandler());'
|
||||
, '});'
|
||||
, '}'
|
||||
, ''
|
||||
, 'app.get(\'/\', routes.index);'
|
||||
, 'app.get(\'/users\', user.list);'
|
||||
, ''
|
||||
, 'http.createServer(app).listen(app.get(\'port\'), function(){'
|
||||
, ' console.log("Express server listening on port " + app.get(\'port\'));'
|
||||
, ' console.log(\'Express server listening on port \' + app.get(\'port\'));'
|
||||
, '});'
|
||||
, ''
|
||||
].join(eol);
|
||||
@@ -279,6 +298,7 @@ function createApplicationAt(path) {
|
||||
|
||||
mkdir(path + '/routes', function(){
|
||||
write(path + '/routes/index.js', index);
|
||||
write(path + '/routes/user.js', users);
|
||||
});
|
||||
|
||||
mkdir(path + '/views', function(){
|
||||
@@ -304,10 +324,10 @@ function createApplicationAt(path) {
|
||||
// CSS Engine support
|
||||
switch (program.css) {
|
||||
case 'less':
|
||||
app = app.replace('{css}', eol + ' app.use(require(\'less-middleware\')({ src: __dirname + \'/public\' }));');
|
||||
app = app.replace('{css}', eol + 'app.use(require(\'less-middleware\')({ src: path.join(__dirname, \'public\') }));');
|
||||
break;
|
||||
case 'stylus':
|
||||
app = app.replace('{css}', eol + ' app.use(require(\'stylus\').middleware(__dirname + \'/public\'));');
|
||||
app = app.replace('{css}', eol + 'app.use(require(\'stylus\').middleware(path.join(__dirname, \'public\')));');
|
||||
break;
|
||||
default:
|
||||
app = app.replace('{css}', '');
|
||||
@@ -315,7 +335,7 @@ function createApplicationAt(path) {
|
||||
|
||||
// Session support
|
||||
app = app.replace('{sess}', program.sessions
|
||||
? eol + ' app.use(express.cookieParser(\'your secret here\'));' + eol + ' app.use(express.session());'
|
||||
? eol + 'app.use(express.cookieParser(\'your secret here\'));' + eol + 'app.use(express.session());'
|
||||
: '');
|
||||
|
||||
// Template support
|
||||
@@ -326,7 +346,7 @@ function createApplicationAt(path) {
|
||||
name: 'application-name'
|
||||
, version: '0.0.1'
|
||||
, private: true
|
||||
, scripts: { start: 'node app' }
|
||||
, scripts: { start: 'node app.js' }
|
||||
, dependencies: {
|
||||
express: version
|
||||
}
|
||||
|
||||
-25
@@ -1,25 +0,0 @@
|
||||
|
||||
var http = require('http');
|
||||
|
||||
var times = 50;
|
||||
|
||||
while (times--) {
|
||||
var req = http.request({
|
||||
port: 3000
|
||||
, method: 'POST'
|
||||
, headers: { 'Content-Type': 'application/x-www-form-urlencoded' }
|
||||
});
|
||||
|
||||
req.on('response', function(res){
|
||||
console.log(res.statusCode);
|
||||
});
|
||||
|
||||
var n = 500000;
|
||||
while (n--) {
|
||||
req.write('foo=bar&bar=baz&');
|
||||
}
|
||||
|
||||
req.write('foo=bar&bar=baz');
|
||||
|
||||
req.end();
|
||||
}
|
||||
@@ -1,181 +0,0 @@
|
||||
|
||||
# app
|
||||
|
||||
Application prototype.
|
||||
|
||||
# app.use()
|
||||
|
||||
Proxy `connect#use()` to apply settings to
|
||||
mounted applications.
|
||||
|
||||
# app.engine()
|
||||
|
||||
Register the given template engine callback `fn`
|
||||
as `ext`.
|
||||
|
||||
By default will `require()` the engine based on the
|
||||
file extension. For example if you try to render
|
||||
a "foo.jade" file Express will invoke the following internally:
|
||||
|
||||
app.engine('jade', require('jade').__express);
|
||||
|
||||
For engines that do not provide `.__express` out of the box,
|
||||
or if you wish to "map" a different extension to the template engine
|
||||
you may use this method. For example mapping the EJS template engine to
|
||||
".html" files
|
||||
|
||||
app.engine('html', require('ejs').renderFile);
|
||||
|
||||
In this case EJS provides a `.renderFile()` method with
|
||||
the same signature that Express expects: `(path, options, callback)`,
|
||||
though note that it aliases this method as `ejs.__express` internally
|
||||
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)
|
||||
library was created to map all of node's popular template
|
||||
engines to follow this convention, thus allowing them to
|
||||
work seemlessly within Express.
|
||||
|
||||
# app.param()
|
||||
|
||||
Map the given param placeholder `name`(s) to the given callback(s).
|
||||
|
||||
Parameter mapping is used to provide pre-conditions to routes
|
||||
which use normalized placeholders. For example a _:user_id_ parameter
|
||||
could automatically load a user's information from the database without
|
||||
any additional code,
|
||||
|
||||
The callback uses the samesignature as middleware, the only differencing
|
||||
being that the value of the placeholder is passed, in this case the _id_
|
||||
of the user. Once the `next()` function is invoked, just like middleware
|
||||
it will continue on to execute the route, or subsequent parameter functions.
|
||||
|
||||
app.param('user_id', function(req, res, next, id){
|
||||
User.find(id, function(err, user){
|
||||
if (err) {
|
||||
next(err);
|
||||
} else if (user) {
|
||||
req.user = user;
|
||||
next();
|
||||
} else {
|
||||
next(new Error('failed to load user'));
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
# app.set()
|
||||
|
||||
Assign `setting` to `val`, or return `setting`'s value.
|
||||
|
||||
app.set('foo', 'bar');
|
||||
app.get('foo');
|
||||
// => "bar"
|
||||
|
||||
Mounted servers inherit their parent server's settings.
|
||||
|
||||
# app.enabled()
|
||||
|
||||
Check if `setting` is enabled (truthy).
|
||||
|
||||
app.enabled('foo')
|
||||
// => false
|
||||
|
||||
app.enable('foo')
|
||||
app.enabled('foo')
|
||||
// => true
|
||||
|
||||
# app.disabled()
|
||||
|
||||
Check if `setting` is disabled.
|
||||
|
||||
app.disabled('foo')
|
||||
// => true
|
||||
|
||||
app.enable('foo')
|
||||
app.disabled('foo')
|
||||
// => false
|
||||
|
||||
# app.enable()
|
||||
|
||||
Enable `setting`.
|
||||
|
||||
# app.disable()
|
||||
|
||||
Disable `setting`.
|
||||
|
||||
# app.configure()
|
||||
|
||||
Configure callback for zero or more envs,
|
||||
when no `env` is specified that callback will
|
||||
be invoked for all environments. Any combination
|
||||
can be used multiple times, in any order desired.
|
||||
|
||||
## Examples
|
||||
|
||||
app.configure(function(){
|
||||
// executed for all envs
|
||||
});
|
||||
|
||||
app.configure('stage', function(){
|
||||
// executed staging env
|
||||
});
|
||||
|
||||
app.configure('stage', 'production', function(){
|
||||
// executed for stage and production
|
||||
});
|
||||
|
||||
## Note
|
||||
|
||||
These callbacks are invoked immediately, and
|
||||
are effectively sugar for the following.
|
||||
|
||||
var env = process.env.NODE_ENV || 'development';
|
||||
|
||||
switch (env) {
|
||||
case 'development':
|
||||
...
|
||||
break;
|
||||
case 'stage':
|
||||
...
|
||||
break;
|
||||
case 'production':
|
||||
...
|
||||
break;
|
||||
}
|
||||
|
||||
# app.all()
|
||||
|
||||
Special-cased "all" method, applying the given route `path`,
|
||||
middleware, and callback to _every_ HTTP method.
|
||||
|
||||
# app.render()
|
||||
|
||||
Render the given view `name` name with `options`
|
||||
and a callback accepting an error and the
|
||||
rendered template string.
|
||||
|
||||
## Example
|
||||
|
||||
app.render('email', { name: 'Tobi' }, function(err, html){
|
||||
// ...
|
||||
})
|
||||
|
||||
# app.listen()
|
||||
|
||||
Listen for connections.
|
||||
|
||||
A node `http.Server` is returned, with this
|
||||
application (which is a `Function`) as its
|
||||
callback. If you wish to create both an HTTP
|
||||
and HTTPS server you may do so with the "http"
|
||||
and "https" modules as shown here.
|
||||
|
||||
var http = require('http')
|
||||
, https = require('https')
|
||||
, express = require('express')
|
||||
, app = express();
|
||||
|
||||
http.createServer(app).listen(80);
|
||||
http.createServer({ ... }, app).listen(443);
|
||||
|
||||
@@ -1,506 +0,0 @@
|
||||
|
||||
# app
|
||||
|
||||
Application prototype.
|
||||
|
||||
# app.use()
|
||||
|
||||
Proxy `connect#use()` to apply settings to
|
||||
mounted applications.
|
||||
|
||||
# app.engine()
|
||||
|
||||
Register the given template engine callback `fn`
|
||||
as `ext`.
|
||||
|
||||
By default will `require()` the engine based on the
|
||||
file extension. For example if you try to render
|
||||
a "foo.jade" file Express will invoke the following internally:
|
||||
|
||||
app.engine('jade', require('jade').__express);
|
||||
|
||||
For engines that do not provide `.__express` out of the box,
|
||||
or if you wish to "map" a different extension to the template engine
|
||||
you may use this method. For example mapping the EJS template engine to
|
||||
".html" files
|
||||
|
||||
app.engine('html', require('ejs').renderFile);
|
||||
|
||||
In this case EJS provides a `.renderFile()` method with
|
||||
the same signature that Express expects: `(path, options, callback)`,
|
||||
though note that it aliases this method as `ejs.__express` internally
|
||||
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)
|
||||
library was created to map all of node's popular template
|
||||
engines to follow this convention, thus allowing them to
|
||||
work seemlessly within Express.
|
||||
|
||||
# app.param()
|
||||
|
||||
Map the given param placeholder `name`(s) to the given callback(s).
|
||||
|
||||
Parameter mapping is used to provide pre-conditions to routes
|
||||
which use normalized placeholders. For example a _:user_id_ parameter
|
||||
could automatically load a user's information from the database without
|
||||
any additional code,
|
||||
|
||||
The callback uses the samesignature as middleware, the only differencing
|
||||
being that the value of the placeholder is passed, in this case the _id_
|
||||
of the user. Once the `next()` function is invoked, just like middleware
|
||||
it will continue on to execute the route, or subsequent parameter functions.
|
||||
|
||||
app.param('user_id', function(req, res, next, id){
|
||||
User.find(id, function(err, user){
|
||||
if (err) {
|
||||
next(err);
|
||||
} else if (user) {
|
||||
req.user = user;
|
||||
next();
|
||||
} else {
|
||||
next(new Error('failed to load user'));
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
# app.set()
|
||||
|
||||
Assign `setting` to `val`, or return `setting`'s value.
|
||||
|
||||
app.set('foo', 'bar');
|
||||
app.get('foo');
|
||||
// => "bar"
|
||||
|
||||
Mounted servers inherit their parent server's settings.
|
||||
|
||||
# app.enabled()
|
||||
|
||||
Check if `setting` is enabled (truthy).
|
||||
|
||||
app.enabled('foo')
|
||||
// => false
|
||||
|
||||
app.enable('foo')
|
||||
app.enabled('foo')
|
||||
// => true
|
||||
|
||||
# app.disabled()
|
||||
|
||||
Check if `setting` is disabled.
|
||||
|
||||
app.disabled('foo')
|
||||
// => true
|
||||
|
||||
app.enable('foo')
|
||||
app.disabled('foo')
|
||||
// => false
|
||||
|
||||
# app.enable()
|
||||
|
||||
Enable `setting`.
|
||||
|
||||
# app.disable()
|
||||
|
||||
Disable `setting`.
|
||||
|
||||
# app.configure()
|
||||
|
||||
Configure callback for zero or more envs,
|
||||
when no `env` is specified that callback will
|
||||
be invoked for all environments. Any combination
|
||||
can be used multiple times, in any order desired.
|
||||
|
||||
## Examples
|
||||
|
||||
app.configure(function(){
|
||||
// executed for all envs
|
||||
});
|
||||
|
||||
app.configure('stage', function(){
|
||||
// executed staging env
|
||||
});
|
||||
|
||||
app.configure('stage', 'production', function(){
|
||||
// executed for stage and production
|
||||
});
|
||||
|
||||
## Note
|
||||
|
||||
These callbacks are invoked immediately, and
|
||||
are effectively sugar for the following.
|
||||
|
||||
var env = process.env.NODE_ENV || 'development';
|
||||
|
||||
switch (env) {
|
||||
case 'development':
|
||||
...
|
||||
break;
|
||||
case 'stage':
|
||||
...
|
||||
break;
|
||||
case 'production':
|
||||
...
|
||||
break;
|
||||
}
|
||||
|
||||
# app.all()
|
||||
|
||||
Special-cased "all" method, applying the given route `path`,
|
||||
middleware, and callback to _every_ HTTP method.
|
||||
|
||||
# app.render()
|
||||
|
||||
Render the given view `name` name with `options`
|
||||
and a callback accepting an error and the
|
||||
rendered template string.
|
||||
|
||||
## Example
|
||||
|
||||
app.render('email', { name: 'Tobi' }, function(err, html){
|
||||
// ...
|
||||
})
|
||||
|
||||
# app.listen()
|
||||
|
||||
Listen for connections.
|
||||
|
||||
A node `http.Server` is returned, with this
|
||||
application (which is a `Function`) as its
|
||||
callback. If you wish to create both an HTTP
|
||||
and HTTPS server you may do so with the "http"
|
||||
and "https" modules as shown here.
|
||||
|
||||
var http = require('http')
|
||||
, https = require('https')
|
||||
, express = require('express')
|
||||
, app = express();
|
||||
|
||||
http.createServer(app).listen(80);
|
||||
http.createServer({ ... }, app).listen(443);
|
||||
|
||||
|
||||
# req
|
||||
|
||||
Request prototype.
|
||||
|
||||
# req.get
|
||||
|
||||
Return request header.
|
||||
|
||||
The `Referrer` header field is special-cased,
|
||||
both `Referrer` and `Referer` are interchangeable.
|
||||
|
||||
## Examples
|
||||
|
||||
req.get('Content-Type');
|
||||
// => "text/plain"
|
||||
|
||||
req.get('content-type');
|
||||
// => "text/plain"
|
||||
|
||||
req.get('Something');
|
||||
// => undefined
|
||||
|
||||
Aliased as `req.header()`.
|
||||
|
||||
# req.accepts()
|
||||
|
||||
Check if the given `type(s)` is acceptable, returning
|
||||
the best match when true, otherwise `undefined`, in which
|
||||
case you should respond with 406 "Not Acceptable".
|
||||
|
||||
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",
|
||||
or an array `["json", "html", "text/plain"]`. When a list
|
||||
or array is given the _best_ match, if any is returned.
|
||||
|
||||
## Examples
|
||||
|
||||
// Accept: text/html
|
||||
req.accepts('html');
|
||||
// => "html"
|
||||
|
||||
// Accept: text/*, application/json
|
||||
req.accepts('html');
|
||||
// => "html"
|
||||
req.accepts('text/html');
|
||||
// => "text/html"
|
||||
req.accepts('json, text');
|
||||
// => "json"
|
||||
req.accepts('application/json');
|
||||
// => "application/json"
|
||||
|
||||
// Accept: text/*, application/json
|
||||
req.accepts('image/png');
|
||||
req.accepts('png');
|
||||
// => undefined
|
||||
|
||||
// Accept: text/*;q=.5, application/json
|
||||
req.accepts(['html', 'json']);
|
||||
req.accepts('html, json');
|
||||
// => "json"
|
||||
|
||||
# req.acceptsCharset()
|
||||
|
||||
Check if the given `charset` is acceptable,
|
||||
otherwise you should respond with 406 "Not Acceptable".
|
||||
|
||||
# req.acceptsLanguage()
|
||||
|
||||
Check if the given `lang` is acceptable,
|
||||
otherwise you should respond with 406 "Not Acceptable".
|
||||
|
||||
# req.param()
|
||||
|
||||
Return the value of param `name` when present or `defaultValue`.
|
||||
|
||||
- Checks route placeholders, ex: _/user/:id_
|
||||
- Checks body params, ex: id=12, {"id":12}
|
||||
- Checks query string params, ex: ?id=12
|
||||
|
||||
To utilize request bodies, `req.body`
|
||||
should be an object. This can be done by using
|
||||
the `connect.bodyParser()` middleware.
|
||||
|
||||
# req.is()
|
||||
|
||||
Check if the incoming request contains the "Content-Type"
|
||||
header field, and it contains the give mime `type`.
|
||||
|
||||
## Examples
|
||||
|
||||
// With Content-Type: text/html; charset=utf-8
|
||||
req.is('html');
|
||||
req.is('text/html');
|
||||
req.is('text/*');
|
||||
// => true
|
||||
|
||||
// When Content-Type is application/json
|
||||
req.is('json');
|
||||
req.is('application/json');
|
||||
req.is('application/*');
|
||||
// => true
|
||||
|
||||
req.is('html');
|
||||
// => false
|
||||
|
||||
|
||||
# res
|
||||
|
||||
Response prototype.
|
||||
|
||||
# res.status()
|
||||
|
||||
Set status `code`.
|
||||
|
||||
# res.send()
|
||||
|
||||
Send a response.
|
||||
|
||||
## Examples
|
||||
|
||||
res.send(new Buffer('wahoo'));
|
||||
res.send({ some: 'json' });
|
||||
res.send('<p>some html</p>');
|
||||
res.send(404, 'Sorry, cant find that');
|
||||
res.send(404);
|
||||
|
||||
# res.json()
|
||||
|
||||
Send JSON response.
|
||||
|
||||
## Examples
|
||||
|
||||
res.json(null);
|
||||
res.json({ user: 'tj' });
|
||||
res.json(500, 'oh noes!');
|
||||
res.json(404, 'I dont have that');
|
||||
|
||||
# res.sendfile()
|
||||
|
||||
Transfer the file at the given `path`.
|
||||
|
||||
Automatically sets the _Content-Type_ response header field.
|
||||
The callback `fn(err)` is invoked when the transfer is complete
|
||||
or when an error occurs. Be sure to check `res.sentHeader`
|
||||
if you wish to attempt responding, as the header and some data
|
||||
may have already been transferred.
|
||||
|
||||
## Options
|
||||
|
||||
- `maxAge` defaulting to 0
|
||||
- `root` root directory for relative filenames
|
||||
|
||||
## Examples
|
||||
|
||||
The following example illustrates how `res.sendfile()` may
|
||||
be used as an alternative for the `static()` middleware for
|
||||
dynamic situations. The code backing `res.sendfile()` is actually
|
||||
the same code, so HTTP cache support etc is identical.
|
||||
|
||||
app.get('/user/:uid/photos/:file', function(req, res){
|
||||
var uid = req.params.uid
|
||||
, file = req.params.file;
|
||||
|
||||
req.user.mayViewFilesFrom(uid, function(yes){
|
||||
if (yes) {
|
||||
res.sendfile('/uploads/' + uid + '/' + file);
|
||||
} else {
|
||||
res.send(403, 'Sorry! you cant see that.');
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
# res.download()
|
||||
|
||||
Transfer the file at the given `path` as an attachment.
|
||||
|
||||
Optionally providing an alternate attachment `filename`,
|
||||
and optional callback `fn(err)`. The callback is invoked
|
||||
when the data transfer is complete, or when an error has
|
||||
ocurred. Be sure to check `res.headerSent` if you plan to respond.
|
||||
|
||||
This method uses `res.sendfile()`.
|
||||
|
||||
# res.format()
|
||||
|
||||
Respond to the Acceptable formats using an `obj`
|
||||
of mime-type callbacks.
|
||||
|
||||
This method uses `req.accepted`, an array of
|
||||
acceptable types ordered by their quality values.
|
||||
When "Accept" is not present the _first_ callback
|
||||
is invoked, otherwise the first match is used. When
|
||||
no match is performed the server responds with
|
||||
406 "Not Acceptable".
|
||||
|
||||
Content-Type is set for you, however if you choose
|
||||
you may alter this within the callback using `res.type()`
|
||||
or `res.set('Content-Type', ...)`.
|
||||
|
||||
res.format({
|
||||
'text/plain': function(){
|
||||
res.send('hey');
|
||||
},
|
||||
|
||||
'text/html': function(){
|
||||
res.send('<p>hey</p>');
|
||||
},
|
||||
|
||||
'appliation/json': function(){
|
||||
res.send({ message: 'hey' });
|
||||
}
|
||||
});
|
||||
|
||||
In addition to canonicalized MIME types you may
|
||||
also use extnames mapped to these types:
|
||||
|
||||
res.format({
|
||||
text: function(){
|
||||
res.send('hey');
|
||||
},
|
||||
|
||||
html: function(){
|
||||
res.send('<p>hey</p>');
|
||||
},
|
||||
|
||||
json: function(){
|
||||
res.send({ message: 'hey' });
|
||||
}
|
||||
});
|
||||
|
||||
By default Express passes an `Error`
|
||||
with a `.status` of 406 to `next(err)`
|
||||
if a match is not made, however you may
|
||||
provide an optional callback `fn` to
|
||||
be invoked instead.
|
||||
|
||||
# res.attachment()
|
||||
|
||||
Set _Content-Disposition_ header to _attachment_ with optional `filename`.
|
||||
|
||||
# res.set
|
||||
|
||||
Set header `field` to `val`, or pass
|
||||
an object of header fields.
|
||||
|
||||
## Examples
|
||||
|
||||
res.set('Accept', 'application/json');
|
||||
res.set({ Accept: 'text/plain', 'X-API-Key': 'tobi' });
|
||||
|
||||
Aliased as `res.header()`.
|
||||
|
||||
# res.get()
|
||||
|
||||
Get value for header `field`.
|
||||
|
||||
# res.clearCookie()
|
||||
|
||||
Clear cookie `name`.
|
||||
|
||||
# res.cookie()
|
||||
|
||||
Set cookie `name` to `val`, with the given `options`.
|
||||
|
||||
## Options
|
||||
|
||||
- `maxAge` max-age in milliseconds, converted to `expires`
|
||||
- `signed` sign the cookie
|
||||
- `path` defaults to "/"
|
||||
|
||||
## Examples
|
||||
|
||||
// "Remember Me" for 15 minutes
|
||||
res.cookie('rememberme', '1', { expires: new Date(Date.now() + 900000), httpOnly: true });
|
||||
|
||||
// save as above
|
||||
res.cookie('rememberme', '1', { maxAge: 900000, httpOnly: true })
|
||||
|
||||
# res.redirect()
|
||||
|
||||
Redirect to the given `url` with optional response `status`
|
||||
defaulting to 302.
|
||||
|
||||
The given `url` can also be the name of a mapped url, for
|
||||
example by default express supports "back" which redirects
|
||||
to the _Referrer_ or _Referer_ headers or "/".
|
||||
|
||||
## Examples
|
||||
|
||||
res.redirect('/foo/bar');
|
||||
res.redirect('http://example.com');
|
||||
res.redirect(301, 'http://example.com');
|
||||
res.redirect('../login'); // /blog/post/1 -> /blog/login
|
||||
|
||||
## Mounting
|
||||
|
||||
When an application is mounted, and `res.redirect()`
|
||||
is given a path that does _not_ lead with "/". For
|
||||
example suppose a "blog" app is mounted at "/blog",
|
||||
the following redirect would result in "/blog/login":
|
||||
|
||||
res.redirect('login');
|
||||
|
||||
While the leading slash would result in a redirect to "/login":
|
||||
|
||||
res.redirect('/login');
|
||||
|
||||
# res.render()
|
||||
|
||||
Render `view` with the given `options` and optional callback `fn`.
|
||||
When a callback function is given a response will _not_ be made
|
||||
automatically, otherwise a response of _200_ and _text/html_ is given.
|
||||
|
||||
## Options
|
||||
|
||||
- `status` Response status code (`res.statusCode`)
|
||||
- `charset` Set the charset (`res.charset`)
|
||||
|
||||
## Reserved locals
|
||||
|
||||
- `cache` boolean hinting to the engine it should cache
|
||||
- `filename` filename of the view being rendered
|
||||
|
||||
@@ -1,107 +0,0 @@
|
||||
|
||||
# req
|
||||
|
||||
Request prototype.
|
||||
|
||||
# req.get
|
||||
|
||||
Return request header.
|
||||
|
||||
The `Referrer` header field is special-cased,
|
||||
both `Referrer` and `Referer` are interchangeable.
|
||||
|
||||
## Examples
|
||||
|
||||
req.get('Content-Type');
|
||||
// => "text/plain"
|
||||
|
||||
req.get('content-type');
|
||||
// => "text/plain"
|
||||
|
||||
req.get('Something');
|
||||
// => undefined
|
||||
|
||||
Aliased as `req.header()`.
|
||||
|
||||
# req.accepts()
|
||||
|
||||
Check if the given `type(s)` is acceptable, returning
|
||||
the best match when true, otherwise `undefined`, in which
|
||||
case you should respond with 406 "Not Acceptable".
|
||||
|
||||
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",
|
||||
or an array `["json", "html", "text/plain"]`. When a list
|
||||
or array is given the _best_ match, if any is returned.
|
||||
|
||||
## Examples
|
||||
|
||||
// Accept: text/html
|
||||
req.accepts('html');
|
||||
// => "html"
|
||||
|
||||
// Accept: text/*, application/json
|
||||
req.accepts('html');
|
||||
// => "html"
|
||||
req.accepts('text/html');
|
||||
// => "text/html"
|
||||
req.accepts('json, text');
|
||||
// => "json"
|
||||
req.accepts('application/json');
|
||||
// => "application/json"
|
||||
|
||||
// Accept: text/*, application/json
|
||||
req.accepts('image/png');
|
||||
req.accepts('png');
|
||||
// => undefined
|
||||
|
||||
// Accept: text/*;q=.5, application/json
|
||||
req.accepts(['html', 'json']);
|
||||
req.accepts('html, json');
|
||||
// => "json"
|
||||
|
||||
# req.acceptsCharset()
|
||||
|
||||
Check if the given `charset` is acceptable,
|
||||
otherwise you should respond with 406 "Not Acceptable".
|
||||
|
||||
# req.acceptsLanguage()
|
||||
|
||||
Check if the given `lang` is acceptable,
|
||||
otherwise you should respond with 406 "Not Acceptable".
|
||||
|
||||
# req.param()
|
||||
|
||||
Return the value of param `name` when present or `defaultValue`.
|
||||
|
||||
- Checks route placeholders, ex: _/user/:id_
|
||||
- Checks body params, ex: id=12, {"id":12}
|
||||
- Checks query string params, ex: ?id=12
|
||||
|
||||
To utilize request bodies, `req.body`
|
||||
should be an object. This can be done by using
|
||||
the `connect.bodyParser()` middleware.
|
||||
|
||||
# req.is()
|
||||
|
||||
Check if the incoming request contains the "Content-Type"
|
||||
header field, and it contains the give mime `type`.
|
||||
|
||||
## Examples
|
||||
|
||||
// With Content-Type: text/html; charset=utf-8
|
||||
req.is('html');
|
||||
req.is('text/html');
|
||||
req.is('text/*');
|
||||
// => true
|
||||
|
||||
// When Content-Type is application/json
|
||||
req.is('json');
|
||||
req.is('application/json');
|
||||
req.is('application/*');
|
||||
// => true
|
||||
|
||||
req.is('html');
|
||||
// => false
|
||||
|
||||
@@ -1,218 +0,0 @@
|
||||
|
||||
# res
|
||||
|
||||
Response prototype.
|
||||
|
||||
# res.status()
|
||||
|
||||
Set status `code`.
|
||||
|
||||
# res.send()
|
||||
|
||||
Send a response.
|
||||
|
||||
## Examples
|
||||
|
||||
res.send(new Buffer('wahoo'));
|
||||
res.send({ some: 'json' });
|
||||
res.send('<p>some html</p>');
|
||||
res.send(404, 'Sorry, cant find that');
|
||||
res.send(404);
|
||||
|
||||
# res.json()
|
||||
|
||||
Send JSON response.
|
||||
|
||||
## Examples
|
||||
|
||||
res.json(null);
|
||||
res.json({ user: 'tj' });
|
||||
res.json(500, 'oh noes!');
|
||||
res.json(404, 'I dont have that');
|
||||
|
||||
# res.sendfile()
|
||||
|
||||
Transfer the file at the given `path`.
|
||||
|
||||
Automatically sets the _Content-Type_ response header field.
|
||||
The callback `fn(err)` is invoked when the transfer is complete
|
||||
or when an error occurs. Be sure to check `res.sentHeader`
|
||||
if you wish to attempt responding, as the header and some data
|
||||
may have already been transferred.
|
||||
|
||||
## Options
|
||||
|
||||
- `maxAge` defaulting to 0
|
||||
- `root` root directory for relative filenames
|
||||
|
||||
## Examples
|
||||
|
||||
The following example illustrates how `res.sendfile()` may
|
||||
be used as an alternative for the `static()` middleware for
|
||||
dynamic situations. The code backing `res.sendfile()` is actually
|
||||
the same code, so HTTP cache support etc is identical.
|
||||
|
||||
app.get('/user/:uid/photos/:file', function(req, res){
|
||||
var uid = req.params.uid
|
||||
, file = req.params.file;
|
||||
|
||||
req.user.mayViewFilesFrom(uid, function(yes){
|
||||
if (yes) {
|
||||
res.sendfile('/uploads/' + uid + '/' + file);
|
||||
} else {
|
||||
res.send(403, 'Sorry! you cant see that.');
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
# res.download()
|
||||
|
||||
Transfer the file at the given `path` as an attachment.
|
||||
|
||||
Optionally providing an alternate attachment `filename`,
|
||||
and optional callback `fn(err)`. The callback is invoked
|
||||
when the data transfer is complete, or when an error has
|
||||
ocurred. Be sure to check `res.headerSent` if you plan to respond.
|
||||
|
||||
This method uses `res.sendfile()`.
|
||||
|
||||
# res.format()
|
||||
|
||||
Respond to the Acceptable formats using an `obj`
|
||||
of mime-type callbacks.
|
||||
|
||||
This method uses `req.accepted`, an array of
|
||||
acceptable types ordered by their quality values.
|
||||
When "Accept" is not present the _first_ callback
|
||||
is invoked, otherwise the first match is used. When
|
||||
no match is performed the server responds with
|
||||
406 "Not Acceptable".
|
||||
|
||||
Content-Type is set for you, however if you choose
|
||||
you may alter this within the callback using `res.type()`
|
||||
or `res.set('Content-Type', ...)`.
|
||||
|
||||
res.format({
|
||||
'text/plain': function(){
|
||||
res.send('hey');
|
||||
},
|
||||
|
||||
'text/html': function(){
|
||||
res.send('<p>hey</p>');
|
||||
},
|
||||
|
||||
'appliation/json': function(){
|
||||
res.send({ message: 'hey' });
|
||||
}
|
||||
});
|
||||
|
||||
In addition to canonicalized MIME types you may
|
||||
also use extnames mapped to these types:
|
||||
|
||||
res.format({
|
||||
text: function(){
|
||||
res.send('hey');
|
||||
},
|
||||
|
||||
html: function(){
|
||||
res.send('<p>hey</p>');
|
||||
},
|
||||
|
||||
json: function(){
|
||||
res.send({ message: 'hey' });
|
||||
}
|
||||
});
|
||||
|
||||
By default Express passes an `Error`
|
||||
with a `.status` of 406 to `next(err)`
|
||||
if a match is not made, however you may
|
||||
provide an optional callback `fn` to
|
||||
be invoked instead.
|
||||
|
||||
# res.attachment()
|
||||
|
||||
Set _Content-Disposition_ header to _attachment_ with optional `filename`.
|
||||
|
||||
# res.set
|
||||
|
||||
Set header `field` to `val`, or pass
|
||||
an object of header fields.
|
||||
|
||||
## Examples
|
||||
|
||||
res.set('Accept', 'application/json');
|
||||
res.set({ Accept: 'text/plain', 'X-API-Key': 'tobi' });
|
||||
|
||||
Aliased as `res.header()`.
|
||||
|
||||
# res.get()
|
||||
|
||||
Get value for header `field`.
|
||||
|
||||
# res.clearCookie()
|
||||
|
||||
Clear cookie `name`.
|
||||
|
||||
# res.cookie()
|
||||
|
||||
Set cookie `name` to `val`, with the given `options`.
|
||||
|
||||
## Options
|
||||
|
||||
- `maxAge` max-age in milliseconds, converted to `expires`
|
||||
- `signed` sign the cookie
|
||||
- `path` defaults to "/"
|
||||
|
||||
## Examples
|
||||
|
||||
// "Remember Me" for 15 minutes
|
||||
res.cookie('rememberme', '1', { expires: new Date(Date.now() + 900000), httpOnly: true });
|
||||
|
||||
// save as above
|
||||
res.cookie('rememberme', '1', { maxAge: 900000, httpOnly: true })
|
||||
|
||||
# res.redirect()
|
||||
|
||||
Redirect to the given `url` with optional response `status`
|
||||
defaulting to 302.
|
||||
|
||||
The given `url` can also be the name of a mapped url, for
|
||||
example by default express supports "back" which redirects
|
||||
to the _Referrer_ or _Referer_ headers or "/".
|
||||
|
||||
## Examples
|
||||
|
||||
res.redirect('/foo/bar');
|
||||
res.redirect('http://example.com');
|
||||
res.redirect(301, 'http://example.com');
|
||||
res.redirect('../login'); // /blog/post/1 -> /blog/login
|
||||
|
||||
## Mounting
|
||||
|
||||
When an application is mounted, and `res.redirect()`
|
||||
is given a path that does _not_ lead with "/". For
|
||||
example suppose a "blog" app is mounted at "/blog",
|
||||
the following redirect would result in "/blog/login":
|
||||
|
||||
res.redirect('login');
|
||||
|
||||
While the leading slash would result in a redirect to "/login":
|
||||
|
||||
res.redirect('/login');
|
||||
|
||||
# res.render()
|
||||
|
||||
Render `view` with the given `options` and optional callback `fn`.
|
||||
When a callback function is given a response will _not_ be made
|
||||
automatically, otherwise a response of _200_ and _text/html_ is given.
|
||||
|
||||
## Options
|
||||
|
||||
- `status` Response status code (`res.statusCode`)
|
||||
- `charset` Set the charset (`res.charset`)
|
||||
|
||||
## Reserved locals
|
||||
|
||||
- `cache` boolean hinting to the engine it should cache
|
||||
- `filename` filename of the view being rendered
|
||||
|
||||
@@ -1,9 +1,8 @@
|
||||
|
||||
/**
|
||||
* Module dependencies.
|
||||
*/
|
||||
|
||||
var express = require('../../lib/express')
|
||||
var express = require('../..')
|
||||
, hash = require('./pass').hash;
|
||||
|
||||
var app = module.exports = express();
|
||||
@@ -50,6 +49,7 @@ hash('foobar', function(err, salt, hash){
|
||||
|
||||
|
||||
// Authenticate using our plain-object database of doom!
|
||||
|
||||
function authenticate(name, pass, fn) {
|
||||
if (!module.parent) console.log('authenticating %s:%s', name, pass);
|
||||
var user = users[name];
|
||||
@@ -79,7 +79,7 @@ app.get('/', function(req, res){
|
||||
});
|
||||
|
||||
app.get('/restricted', restrict, function(req, res){
|
||||
res.send('Wahoo! restricted area');
|
||||
res.send('Wahoo! restricted area, click to <a href="/logout">logout</a>');
|
||||
});
|
||||
|
||||
app.get('/logout', function(req, res){
|
||||
@@ -91,11 +91,6 @@ app.get('/logout', function(req, res){
|
||||
});
|
||||
|
||||
app.get('/login', function(req, res){
|
||||
if (req.session.user) {
|
||||
req.session.success = 'Authenticated as ' + req.session.user.name
|
||||
+ ' click to <a href="/logout">logout</a>. '
|
||||
+ ' You may now access <a href="/restricted">/restricted</a>.';
|
||||
}
|
||||
res.render('login');
|
||||
});
|
||||
|
||||
@@ -109,6 +104,9 @@ app.post('/login', function(req, res){
|
||||
// in the session store to be retrieved,
|
||||
// or in this case the entire user object
|
||||
req.session.user = user;
|
||||
req.session.success = 'Authenticated as ' + user.name
|
||||
+ ' click to <a href="/logout">logout</a>. '
|
||||
+ ' You may now access <a href="/restricted">/restricted</a>.';
|
||||
res.redirect('back');
|
||||
});
|
||||
} else {
|
||||
@@ -123,4 +121,4 @@ app.post('/login', function(req, res){
|
||||
if (!module.parent) {
|
||||
app.listen(3000);
|
||||
console.log('Express started on port 3000');
|
||||
}
|
||||
}
|
||||
|
||||
@@ -31,7 +31,9 @@ var iterations = 12000;
|
||||
|
||||
exports.hash = function (pwd, salt, fn) {
|
||||
if (3 == arguments.length) {
|
||||
crypto.pbkdf2(pwd, salt, iterations, len, fn);
|
||||
crypto.pbkdf2(pwd, salt, iterations, len, function(err, hash){
|
||||
fn(err, (new Buffer(hash, 'binary')).toString('base64'));
|
||||
});
|
||||
} else {
|
||||
fn = salt;
|
||||
crypto.randomBytes(len, function(err, salt){
|
||||
@@ -39,8 +41,8 @@ exports.hash = function (pwd, salt, fn) {
|
||||
salt = salt.toString('base64');
|
||||
crypto.pbkdf2(pwd, salt, iterations, len, function(err, hash){
|
||||
if (err) return fn(err);
|
||||
fn(null, salt, hash);
|
||||
fn(null, salt, (new Buffer(hash, 'binary')).toString('base64'));
|
||||
});
|
||||
});
|
||||
}
|
||||
};
|
||||
};
|
||||
@@ -0,0 +1,2 @@
|
||||
</body>
|
||||
</html>
|
||||
@@ -1,7 +1,7 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<title>Authentication Example</title>
|
||||
<title><%= title %></title>
|
||||
<style>
|
||||
body {
|
||||
padding: 50px;
|
||||
@@ -16,6 +16,3 @@
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<%- body %>
|
||||
</body>
|
||||
</html>
|
||||
@@ -1,3 +1,7 @@
|
||||
|
||||
<% var title = 'Authentication Example' %>
|
||||
<% include head %>
|
||||
|
||||
<h1>Login</h1>
|
||||
<%- message %>
|
||||
Try accessing <a href="/restricted">/restricted</a>, then authenticate with "tj" and "foobar".
|
||||
@@ -13,4 +17,6 @@ Try accessing <a href="/restricted">/restricted</a>, then authenticate with "tj"
|
||||
<p>
|
||||
<input type="submit" value="Login">
|
||||
</p>
|
||||
</form>
|
||||
</form>
|
||||
|
||||
<% include foot %>
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
style
|
||||
style.
|
||||
body {
|
||||
padding: 50px;
|
||||
font: 16px "Helvetica Neue", Helvetica;
|
||||
|
||||
@@ -1,8 +1,9 @@
|
||||
|
||||
var express = require('../../')
|
||||
, app = module.exports = express()
|
||||
, users = require('./db');
|
||||
|
||||
// so either you can deal with different types of formatting
|
||||
// for expected response in index.js
|
||||
app.get('/', function(req, res){
|
||||
res.format({
|
||||
html: function(){
|
||||
@@ -24,12 +25,13 @@ app.get('/', function(req, res){
|
||||
});
|
||||
|
||||
// or you could write a tiny middleware like
|
||||
// this to abstract make things a bit more declarative:
|
||||
// this to add a layer of abstraction
|
||||
// and make things a bit more declarative:
|
||||
|
||||
function format(mod) {
|
||||
var obj = require(mod);
|
||||
function format(requestHandlerName) {
|
||||
var requestHandler = require(requestHandlerName);
|
||||
return function(req, res){
|
||||
res.format(obj);
|
||||
res.format(requestHandler);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -38,4 +40,4 @@ app.get('/users', format('./users'));
|
||||
if (!module.parent) {
|
||||
app.listen(3000);
|
||||
console.log('listening on port 3000');
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,46 @@
|
||||
/**
|
||||
* Module dependencies.
|
||||
*/
|
||||
|
||||
var express = require('../..')
|
||||
, app = express()
|
||||
, api = express();
|
||||
|
||||
// app middleware
|
||||
|
||||
app.use(express.static(__dirname + '/public'));
|
||||
|
||||
// api middleware
|
||||
|
||||
api.use(express.logger('dev'));
|
||||
api.use(express.bodyParser());
|
||||
|
||||
/**
|
||||
* CORS support.
|
||||
*/
|
||||
|
||||
api.all('*', function(req, res, next){
|
||||
if (!req.get('Origin')) return next();
|
||||
// use "*" here to accept any origin
|
||||
res.set('Access-Control-Allow-Origin', 'http://localhost:3000');
|
||||
res.set('Access-Control-Allow-Methods', 'GET, POST');
|
||||
res.set('Access-Control-Allow-Headers', 'X-Requested-With, Content-Type');
|
||||
// res.set('Access-Control-Allow-Max-Age', 3600);
|
||||
if ('OPTIONS' == req.method) return res.send(200);
|
||||
next();
|
||||
});
|
||||
|
||||
/**
|
||||
* POST a user.
|
||||
*/
|
||||
|
||||
api.post('/user', function(req, res){
|
||||
console.log(req.body);
|
||||
res.send(201);
|
||||
});
|
||||
|
||||
app.listen(3000);
|
||||
api.listen(3001);
|
||||
|
||||
console.log('app listening on 3000');
|
||||
console.log('api listening on 3001');
|
||||
@@ -0,0 +1,12 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<body>
|
||||
<script>
|
||||
var req = new XMLHttpRequest;
|
||||
req.open('POST', 'http://localhost:3001/user', false);
|
||||
req.setRequestHeader('Content-Type', 'application/json');
|
||||
req.send('{"name":"tobi","species":"ferret"}');
|
||||
console.log(req.responseText);
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
@@ -31,16 +31,20 @@ app.set('view engine', 'html');
|
||||
|
||||
// Dummy users
|
||||
var users = [
|
||||
{ name: 'tobi', email: 'tobi@learnboost.com' }
|
||||
, { name: 'loki', email: 'loki@learnboost.com' }
|
||||
, { name: 'jane', email: 'jane@learnboost.com' }
|
||||
{ name: 'tobi', email: 'tobi@learnboost.com' },
|
||||
{ name: 'loki', email: 'loki@learnboost.com' },
|
||||
{ name: 'jane', email: 'jane@learnboost.com' }
|
||||
];
|
||||
|
||||
app.get('/', function(req, res){
|
||||
res.render('users', { users: users });
|
||||
res.render('users', {
|
||||
users: users,
|
||||
title: "EJS example",
|
||||
header: "Some users"
|
||||
});
|
||||
});
|
||||
|
||||
if (!module.parent) {
|
||||
app.listen(3000);
|
||||
console.log('Express app started on port 3000');
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,2 @@
|
||||
</body>
|
||||
</html>
|
||||
@@ -0,0 +1,13 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<title> <%= title %> </title>
|
||||
<style type="text/css">
|
||||
body {
|
||||
padding: 50px;
|
||||
font: 13px Helvetica, Arial, sans-serif;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
@@ -1,6 +1,10 @@
|
||||
<% include header.html %>
|
||||
|
||||
<h1>Users</h1>
|
||||
<ul id="users">
|
||||
<% users.forEach(function(user){ %>
|
||||
<li><%= user.name %> <%= user.email %></li>
|
||||
<li><%= user.name %> <<%= user.email %>></li>
|
||||
<% }) %>
|
||||
</ul>
|
||||
</ul>
|
||||
|
||||
<% include footer.html %>
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
|
||||
/**
|
||||
* Module dependencies.
|
||||
*/
|
||||
@@ -7,9 +6,21 @@ var express = require('../../')
|
||||
, app = module.exports = express()
|
||||
, silent = 'test' == process.env.NODE_ENV;
|
||||
|
||||
// general config
|
||||
app.set('views', __dirname + '/views');
|
||||
app.set('view engine', 'jade');
|
||||
|
||||
// our custom "verbose errors" setting
|
||||
// which we can use in the templates
|
||||
// via settings['verbose errors']
|
||||
app.enable('verbose errors');
|
||||
|
||||
// disable them in production
|
||||
// use $ NODE_ENV=production node examples/error-pages
|
||||
if ('production' == app.settings.env) {
|
||||
app.disable('verbose errors');
|
||||
}
|
||||
|
||||
app.use(express.favicon());
|
||||
|
||||
silent || app.use(express.logger('dev'));
|
||||
@@ -32,9 +43,10 @@ app.use(app.router);
|
||||
// $ curl http://localhost:3000/notfound -H "Accept: text/plain"
|
||||
|
||||
app.use(function(req, res, next){
|
||||
res.status(404);
|
||||
|
||||
// respond with html page
|
||||
if (req.accepts('html')) {
|
||||
res.status(404);
|
||||
res.render('404', { url: req.url });
|
||||
return;
|
||||
}
|
||||
@@ -76,16 +88,21 @@ app.get('/', function(req, res){
|
||||
});
|
||||
|
||||
app.get('/404', function(req, res, next){
|
||||
// trigger a 404 since no other middleware
|
||||
// will match /404 after this one, and we're not
|
||||
// responding here
|
||||
next();
|
||||
});
|
||||
|
||||
app.get('/403', function(req, res, next){
|
||||
// trigger a 403 error
|
||||
var err = new Error('not allowed!');
|
||||
err.status = 403;
|
||||
next(err);
|
||||
});
|
||||
|
||||
app.get('/500', function(req, res, next){
|
||||
// trigger a generic (500) error
|
||||
next(new Error('keyboard cat!'));
|
||||
});
|
||||
|
||||
|
||||
@@ -7,4 +7,7 @@ extends error
|
||||
|
||||
block content
|
||||
h1 Error: #{error.message}
|
||||
pre= error.stack
|
||||
if settings['verbose errors']
|
||||
pre= error.stack
|
||||
else
|
||||
p An error ocurred!
|
||||
@@ -8,8 +8,8 @@ block content
|
||||
| visit
|
||||
a(href="/500") 500
|
||||
li
|
||||
| visit
|
||||
| visit
|
||||
a(href="/404") 404
|
||||
li
|
||||
| visit
|
||||
| visit
|
||||
a(href='/403') 403
|
||||
@@ -1,7 +1,7 @@
|
||||
html
|
||||
head
|
||||
title Express
|
||||
script
|
||||
script.
|
||||
// call this whatever you like,
|
||||
// or dump them into individual
|
||||
// props like "var user ="
|
||||
@@ -10,5 +10,5 @@ html
|
||||
h1 Expose client data
|
||||
p The following was exposed to the client:
|
||||
pre
|
||||
script
|
||||
script.
|
||||
document.write(JSON.stringify(data, null, 2))
|
||||
@@ -9,10 +9,9 @@ var express = require('../../lib/express');
|
||||
|
||||
var pub = __dirname + '/public';
|
||||
|
||||
// Auto-compile sass to css with "compiler"
|
||||
// and then serve with connect's staticProvider
|
||||
// setup middleware
|
||||
|
||||
var app = express.createServer();
|
||||
var app = express();
|
||||
app.use(app.router);
|
||||
app.use(express.static(pub));
|
||||
app.use(express.errorHandler());
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
body {
|
||||
padding: 50px 80px;
|
||||
font: 14px "Helvetica Nueue", "Lucida Grande", Arial, sans-serif;}
|
||||
font: 14px "Helvetica Nueue", "Lucida Grande", Arial, sans-serif;
|
||||
}
|
||||
|
||||
@@ -3,9 +3,9 @@
|
||||
* Module dependencies.
|
||||
*/
|
||||
|
||||
var express = require('../../')
|
||||
var express = require('../..')
|
||||
, fs = require('fs')
|
||||
, md = require('github-flavored-markdown').parse;
|
||||
, md = require('marked').parse;
|
||||
|
||||
var app = module.exports = express();
|
||||
|
||||
@@ -42,4 +42,4 @@ app.get('/fail', function(req, res){
|
||||
if (!module.parent) {
|
||||
app.listen(3000);
|
||||
console.log('Express started on port 3000');
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
* Module dependencies.
|
||||
*/
|
||||
|
||||
var express = require('../../')
|
||||
var express = require('../..')
|
||||
, format = require('util').format;
|
||||
|
||||
var app = module.exports = express()
|
||||
@@ -1,4 +1,3 @@
|
||||
|
||||
var express = require('../..');
|
||||
|
||||
var app = module.exports = express();
|
||||
@@ -58,10 +57,10 @@ app.use(function(req, res, next){
|
||||
});
|
||||
*/
|
||||
|
||||
next();
|
||||
// empty or "flush" the messages so they
|
||||
// don't build up
|
||||
req.session.messages = [];
|
||||
next();
|
||||
});
|
||||
|
||||
// load controllers
|
||||
@@ -90,4 +89,4 @@ app.use(function(req, res, next){
|
||||
if (!module.parent) {
|
||||
app.listen(3000);
|
||||
console.log('\n listening on port 3000\n');
|
||||
}
|
||||
}
|
||||
|
||||
@@ -37,7 +37,6 @@ module.exports = function(parent, options){
|
||||
case 'show':
|
||||
method = 'get';
|
||||
path = '/' + name + '/:' + name + '_id';
|
||||
app[method](path, obj[key]);
|
||||
break;
|
||||
case 'list':
|
||||
method = 'get';
|
||||
|
||||
@@ -0,0 +1,54 @@
|
||||
|
||||
// first:
|
||||
// $ npm install redis online
|
||||
// $ redis-server
|
||||
|
||||
/**
|
||||
* Module dependencies.
|
||||
*/
|
||||
|
||||
var express = require('../..')
|
||||
, online = require('online')
|
||||
, redis = require('redis')
|
||||
, db = redis.createClient();
|
||||
|
||||
// online
|
||||
|
||||
online = online(db);
|
||||
|
||||
// app
|
||||
|
||||
var app = express();
|
||||
|
||||
// activity tracking, in this case using
|
||||
// the UA string, you would use req.user.id etc
|
||||
|
||||
app.use(function(req, res, next){
|
||||
// fire-and-forget
|
||||
online.add(req.headers['user-agent']);
|
||||
next();
|
||||
});
|
||||
|
||||
/**
|
||||
* List helper.
|
||||
*/
|
||||
|
||||
function list(ids) {
|
||||
return '<ul>' + ids.map(function(id){
|
||||
return '<li>' + id + '</li>';
|
||||
}).join('') + '</ul>';
|
||||
}
|
||||
|
||||
/**
|
||||
* GET users online.
|
||||
*/
|
||||
|
||||
app.get('/', function(req, res, next){
|
||||
online.last(5, function(err, ids){
|
||||
if (err) return next(err);
|
||||
res.send('<p>Users online: ' + ids.length + '</p>' + list(ids));
|
||||
});
|
||||
});
|
||||
|
||||
app.listen(3000);
|
||||
console.log('listening on port 3000');
|
||||
@@ -1,32 +0,0 @@
|
||||
|
||||
/**
|
||||
* Module dependencies.
|
||||
*/
|
||||
|
||||
var express = require('../../lib/express');
|
||||
|
||||
var app = express.createServer();
|
||||
|
||||
// Optional since express defaults to CWD/views
|
||||
|
||||
app.set('views', __dirname + '/views');
|
||||
|
||||
// Set our default template engine to "jade"
|
||||
// which prevents the need for extensions
|
||||
// (although you can still mix and match)
|
||||
app.set('view engine', 'jade');
|
||||
|
||||
// Dummy record
|
||||
var ninja = {
|
||||
name: 'leonardo',
|
||||
summary: { email: 'hunter.loftis+github@gmail.com', master: 'splinter', description: 'peaceful leader' },
|
||||
weapons: ['katana', 'fists', 'shell'],
|
||||
victims: ['shredder', 'brain', 'beebop', 'rocksteady']
|
||||
};
|
||||
|
||||
app.get('/', function(req, res){
|
||||
res.render('ninja', { ninja: ninja });
|
||||
});
|
||||
|
||||
app.listen(3000);
|
||||
console.log('Express app started on port 3000');
|
||||
@@ -1,5 +0,0 @@
|
||||
!!!
|
||||
html
|
||||
head
|
||||
title Partials Example
|
||||
body!= body
|
||||
@@ -1 +0,0 @@
|
||||
li= value
|
||||
@@ -1 +0,0 @@
|
||||
li.weapon= weapon
|
||||
@@ -1,22 +0,0 @@
|
||||
h1= ninja.name
|
||||
|
||||
// file, partial name, and partial object all match ('summary')
|
||||
// the partial filename prefix '_' is completely optional.
|
||||
|
||||
// In this case we need to specify ninja.summary as the object
|
||||
// option, since it is a "plain" object Express cannot otherwise
|
||||
// tell if it is intended to be locals, or THE summary object
|
||||
#summary!= partial('summary', { object: ninja.summary })
|
||||
|
||||
// file, partial name = '_weapon', resolves to 'weapon' object within partial
|
||||
#weapons
|
||||
h2 Weapons
|
||||
// the weapon partial is rendered once per item in
|
||||
// the weapons array or "collection"
|
||||
ul!= partial('weapon', ninja.weapons)
|
||||
|
||||
// partial name 'victim' resolves to 'victim.jade'
|
||||
// or 'victim/index.jade', providing the "victim" local
|
||||
#victims
|
||||
h2 Victims
|
||||
ul!= partial('victim', ninja.victims)
|
||||
@@ -1,4 +0,0 @@
|
||||
h2 Summary
|
||||
p= summary.email
|
||||
p= summary.description
|
||||
p taught by master #{summary.master}
|
||||
@@ -1,5 +0,0 @@
|
||||
// this is insane overkill, I do not recommend
|
||||
// doing tiny partials like this as it gets expensive
|
||||
// with collections, however this illustrates the new
|
||||
// partial lookup mechanism
|
||||
!= partial('../../li', { object: victim, as: 'value' })
|
||||
@@ -1,26 +0,0 @@
|
||||
|
||||
/**
|
||||
* Module dependencies.
|
||||
*/
|
||||
|
||||
var vm = require('vm')
|
||||
, fs = require('fs');
|
||||
|
||||
module.exports = function(app, db){
|
||||
var dir = __dirname + '/routes';
|
||||
// grab a list of our route files
|
||||
fs.readdirSync(dir).forEach(function(file){
|
||||
var str = fs.readFileSync(dir + '/' + file, 'utf8');
|
||||
// inject some pseudo globals by evaluating
|
||||
// the file with vm.runInNewContext()
|
||||
// instead of loading it with require(). require's
|
||||
// internals use similar, so dont be afraid of "boot time".
|
||||
var context = { app: app, db: db };
|
||||
// we have to merge the globals for console, process etc
|
||||
for (var key in global) context[key] = global[key];
|
||||
// note that this is essentially no different than ... just using
|
||||
// global variables, though it's only YOUR code that could influence
|
||||
// them, which is a bonus.
|
||||
vm.runInNewContext(str, context, file);
|
||||
});
|
||||
};
|
||||
@@ -1,20 +0,0 @@
|
||||
|
||||
/**
|
||||
* Module dependencies.
|
||||
*/
|
||||
|
||||
var express = require('../../lib/express')
|
||||
, app = express()
|
||||
, db = { users: [] };
|
||||
|
||||
app.set('views', __dirname + '/views');
|
||||
app.set('view engine', 'jade');
|
||||
app.use(express.bodyParser());
|
||||
|
||||
// pretend db is a database, could be
|
||||
// whatever you like
|
||||
require('./boot')(app, db);
|
||||
|
||||
app.listen(3000);
|
||||
console.log('Express app started on port 3000');
|
||||
|
||||
@@ -1,4 +0,0 @@
|
||||
|
||||
app.get('/', function(req, res){
|
||||
res.render('index');
|
||||
});
|
||||
@@ -1,18 +0,0 @@
|
||||
|
||||
app.get('/users', function(req, res){
|
||||
res.render('user/list', { users: db.users });
|
||||
});
|
||||
|
||||
app.get('/user/add', function(req, res){
|
||||
res.render('user/add');
|
||||
});
|
||||
|
||||
app.post('/user', function(req, res){
|
||||
var user = req.body.user;
|
||||
db.users.push(user);
|
||||
res.redirect('/users');
|
||||
});
|
||||
|
||||
app.get('/user/:id', function(req, res){
|
||||
res.render('user');
|
||||
});
|
||||
@@ -1,8 +0,0 @@
|
||||
|
||||
extends layout
|
||||
|
||||
block content
|
||||
h2 Route sharing example
|
||||
ul
|
||||
li: a(href='/user/add') Add user
|
||||
li: a(href='/users') User list
|
||||
@@ -1,11 +0,0 @@
|
||||
doctype html
|
||||
html
|
||||
head
|
||||
title Route loading example
|
||||
style
|
||||
body {
|
||||
padding: 50px;
|
||||
font: 14px/1.5 solid helvetica, arial, sans-serif;
|
||||
}
|
||||
body
|
||||
block content
|
||||
@@ -1,9 +0,0 @@
|
||||
|
||||
extends ../layout
|
||||
|
||||
block content
|
||||
h2 Add a user
|
||||
form(action='/user', method='post')
|
||||
p: input(type='text', name='user[name]', placeholder='Username')
|
||||
p: input(type='text', name='user[email]', placeholder='Email')
|
||||
p: input(type='submit', value='Add')
|
||||
@@ -1,10 +0,0 @@
|
||||
|
||||
extends ../layout
|
||||
|
||||
block content
|
||||
h1= user.name
|
||||
table
|
||||
tbody
|
||||
tr
|
||||
td Email
|
||||
td= user.email
|
||||
@@ -1,10 +0,0 @@
|
||||
|
||||
extends ../layout
|
||||
|
||||
block content
|
||||
h1 Users
|
||||
if users.length
|
||||
for user in users
|
||||
include index
|
||||
else
|
||||
p No users, head over to <a href='/user/add'>/user/add</a> to create one.
|
||||
@@ -4,7 +4,7 @@
|
||||
|
||||
var express = require('../../lib/express');
|
||||
|
||||
var app = express.createServer();
|
||||
var app = express();
|
||||
|
||||
// Example requests:
|
||||
// curl http://localhost:3000/user/0
|
||||
@@ -3,17 +3,19 @@
|
||||
* Module dependencies.
|
||||
*/
|
||||
|
||||
var express = require('../../lib/express')
|
||||
, app = express.createServer()
|
||||
var express = require('../..')
|
||||
, app = express()
|
||||
, site = require('./site')
|
||||
, post = require('./post')
|
||||
, user = require('./user');
|
||||
|
||||
// Config
|
||||
|
||||
app.set('view engine', 'ejs');
|
||||
app.set('view engine', 'jade');
|
||||
app.set('views', __dirname + '/views');
|
||||
app.use(express.logger('dev'));
|
||||
app.use(express.cookieParser());
|
||||
app.use(express.bodyParser());
|
||||
app.use(express.methodOverride());
|
||||
app.use(express.static(__dirname + '/public'));
|
||||
|
||||
@@ -35,4 +37,4 @@ app.put('/user/:id/edit', user.update);
|
||||
app.get('/posts', post.list);
|
||||
|
||||
app.listen(3000);
|
||||
console.log('Express app started on port 3000');
|
||||
console.log('Express app started on port 3000');
|
||||
@@ -2,9 +2,9 @@
|
||||
// Fake posts database
|
||||
|
||||
var posts = [
|
||||
{ title: 'Foo', body: 'some foo bar' }
|
||||
, { title: 'Foo bar', body: 'more foo bar' }
|
||||
, { title: 'Foo bar baz', body: 'more foo bar baz' }
|
||||
{ title: 'Foo', body: 'some foo bar' },
|
||||
{ title: 'Foo bar', body: 'more foo bar' },
|
||||
{ title: 'Foo bar baz', body: 'more foo bar baz' }
|
||||
];
|
||||
|
||||
exports.list = function(req, res){
|
||||
|
||||
@@ -11,10 +11,10 @@ a.edit {
|
||||
opacity: .3;
|
||||
}
|
||||
a.edit::before {
|
||||
content: '[ ';
|
||||
content: ' [';
|
||||
}
|
||||
a.edit::after {
|
||||
content: ' ]';
|
||||
content: ']';
|
||||
}
|
||||
dt {
|
||||
font-weight: bold;
|
||||
|
||||
@@ -2,8 +2,8 @@
|
||||
// Fake user database
|
||||
|
||||
var users = [
|
||||
{ name: 'TJ', email: 'tj@vision-media.ca' }
|
||||
, { name: 'Tobi', email: 'tobi@vision-media.ca' }
|
||||
{ name: 'TJ', email: 'tj@vision-media.ca' },
|
||||
{ name: 'Tobi', email: 'tobi@vision-media.ca' }
|
||||
];
|
||||
|
||||
exports.list = function(req, res){
|
||||
@@ -22,15 +22,15 @@ exports.load = function(req, res, next){
|
||||
|
||||
exports.view = function(req, res){
|
||||
res.render('users/view', {
|
||||
title: 'Viewing user ' + req.user.name
|
||||
, user: req.user
|
||||
title: 'Viewing user ' + req.user.name,
|
||||
user: req.user
|
||||
});
|
||||
};
|
||||
|
||||
exports.edit = function(req, res){
|
||||
res.render('users/edit', {
|
||||
title: 'Editing user ' + req.user.name
|
||||
, user: req.user
|
||||
title: 'Editing user ' + req.user.name,
|
||||
user: req.user
|
||||
});
|
||||
};
|
||||
|
||||
|
||||
@@ -1,4 +0,0 @@
|
||||
<ul>
|
||||
<li>Visit the <a href="/users">users</a> page</li>
|
||||
<li>Visit the <a href="/posts">posts</a> page</li>
|
||||
</ul>
|
||||
@@ -0,0 +1,6 @@
|
||||
extends layout
|
||||
|
||||
block content
|
||||
ul
|
||||
li Visit the <a href="/users">users</a> page
|
||||
li Visit the <a href="/posts">posts</a> page
|
||||
@@ -1,9 +0,0 @@
|
||||
<html>
|
||||
<head>
|
||||
<title><%= title %></title>
|
||||
<link href="/style.css" rel="stylesheet" />
|
||||
</head>
|
||||
<body>
|
||||
<%- body %>
|
||||
</body>
|
||||
</html>
|
||||
@@ -0,0 +1,6 @@
|
||||
html
|
||||
head
|
||||
title= title
|
||||
link(href="/style.css", rel="stylesheet")
|
||||
body
|
||||
block content
|
||||
@@ -1,7 +0,0 @@
|
||||
<h1>Posts</h1>
|
||||
<dl id="posts">
|
||||
<% posts.forEach(function(post){ %>
|
||||
<dt><%= post.title %></dt>
|
||||
<dd><%= post.body %></dd>
|
||||
<% }) %>
|
||||
</dl>
|
||||
@@ -0,0 +1,8 @@
|
||||
extends ../layout
|
||||
|
||||
block content
|
||||
h1 Posts
|
||||
dl#posts
|
||||
for post in posts
|
||||
dt= post.title
|
||||
dd= post.body
|
||||
@@ -1,9 +0,0 @@
|
||||
<h1>Editing <%= user.name %></h1>
|
||||
<div id="user">
|
||||
<form method="post">
|
||||
<input type="hidden" value="put" name="_method" />
|
||||
<p>Name: <input type="text" value="<%= user.name %>" name="user[name]"/></p>
|
||||
<p>Email: <input type="text" value="<%= user.email %>" name="user[email]"/></p>
|
||||
<p><input type="submit" value="Save" /></p>
|
||||
</form>
|
||||
</div>
|
||||
@@ -0,0 +1,13 @@
|
||||
extends ../layout
|
||||
|
||||
block content
|
||||
h1 Editing #{user.name}
|
||||
#user
|
||||
form(method="post")
|
||||
input(type="hidden", value="put", name="_method")
|
||||
p Name:
|
||||
input(type="text", value= user.name, name="user[name]")
|
||||
p Email:
|
||||
input(type="text", value= user.email, name="user[email]")
|
||||
p
|
||||
input(type="submit", value="Save")
|
||||
@@ -1,9 +0,0 @@
|
||||
<h1>Users</h1>
|
||||
<ul id="users">
|
||||
<% users.forEach(function(user, id){ %>
|
||||
<li>
|
||||
<a href="/user/<%= id %>"><%= user.name %></a>
|
||||
<a class="edit" href="/user/<%= id %>/edit">edit</a>
|
||||
</li>
|
||||
<% }) %>
|
||||
</ul>
|
||||
@@ -0,0 +1,9 @@
|
||||
extends ../layout
|
||||
|
||||
block content
|
||||
h1 Users
|
||||
#users
|
||||
for user, i in users
|
||||
li
|
||||
a(href="/user/#{i}")= user.name
|
||||
a.edit(href="/user/#{i}/edit") edit
|
||||
@@ -1,4 +0,0 @@
|
||||
<h1><%= user.name %></h1>
|
||||
<div id="user">
|
||||
<p>Email: <%= user.email %></p>
|
||||
</div>
|
||||
@@ -0,0 +1,6 @@
|
||||
extends ../layout
|
||||
|
||||
block content
|
||||
h1= user.name
|
||||
#user
|
||||
p Email: #{user.email}
|
||||
@@ -1,44 +0,0 @@
|
||||
|
||||
/**
|
||||
* Module dependencies.
|
||||
*/
|
||||
|
||||
var express = require('../../')
|
||||
, path = require('path')
|
||||
, exec = require('child_process').exec
|
||||
, fs = require('fs');
|
||||
|
||||
/**
|
||||
* Error handler.
|
||||
*/
|
||||
|
||||
function errorHandler(voice) {
|
||||
return function(err, req, res, next) {
|
||||
var parts = err.stack.split('\n')[1].split(/[()]/)[1].split(':')
|
||||
, filename = parts.shift()
|
||||
, basename = path.basename(filename)
|
||||
, lineno = parts.shift()
|
||||
, col = parts.shift()
|
||||
, lines = fs.readFileSync(filename, 'utf8').split('\n')
|
||||
, line = lines[lineno - 1].replace(/\./, ' ');
|
||||
|
||||
exec('say -v "' + voice + '" '
|
||||
+ err.message
|
||||
+ ' on line ' + lineno
|
||||
+ ' of ' + basename + '.'
|
||||
+ ' The contents of this line is '
|
||||
+ ' "' + line + '".');
|
||||
|
||||
res.send(500);
|
||||
}
|
||||
}
|
||||
|
||||
var app = express.createServer();
|
||||
|
||||
app.get('/', function(request, response){
|
||||
if (request.is(foo)) response.end('bar');
|
||||
});
|
||||
|
||||
app.use(errorHandler('Vicki'));
|
||||
|
||||
app.listen(3000);
|
||||
@@ -0,0 +1,14 @@
|
||||
|
||||
var search = document.querySelector('[type=search]');
|
||||
var code = document.querySelector('pre');
|
||||
|
||||
search.addEventListener('keyup', function(){
|
||||
var xhr = new XMLHttpRequest;
|
||||
xhr.open('GET', '/search/' + search.value, true);
|
||||
xhr.onreadystatechange = function(){
|
||||
if (4 == xhr.readyState) {
|
||||
code.textContent = xhr.responseText;
|
||||
}
|
||||
};
|
||||
xhr.send();
|
||||
}, false);
|
||||
@@ -0,0 +1,61 @@
|
||||
|
||||
// first:
|
||||
// $ npm install redis
|
||||
// $ redis-server
|
||||
|
||||
/**
|
||||
* Module dependencies.
|
||||
*/
|
||||
|
||||
var express = require('../..')
|
||||
, redis = require('redis')
|
||||
, db = redis.createClient();
|
||||
|
||||
// npm install redis
|
||||
|
||||
var app = express();
|
||||
|
||||
app.set('view engine', 'jade');
|
||||
app.set('views', __dirname);
|
||||
|
||||
// populate search
|
||||
|
||||
db.sadd('ferret', 'tobi');
|
||||
db.sadd('ferret', 'loki');
|
||||
db.sadd('ferret', 'jane');
|
||||
db.sadd('cat', 'manny');
|
||||
db.sadd('cat', 'luna');
|
||||
|
||||
/**
|
||||
* GET the search page.
|
||||
*/
|
||||
|
||||
app.get('/', function(req, res){
|
||||
res.render('search');
|
||||
});
|
||||
|
||||
/**
|
||||
* GET search for :query.
|
||||
*/
|
||||
|
||||
app.get('/search/:query?', function(req, res){
|
||||
var query = req.params.query;
|
||||
db.smembers(query, function(err, vals){
|
||||
if (err) return res.send(500);
|
||||
res.send(vals);
|
||||
});
|
||||
});
|
||||
|
||||
/**
|
||||
* 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');
|
||||
});
|
||||
|
||||
app.listen(3000);
|
||||
console.log('app listening on port 3000');
|
||||
@@ -0,0 +1,15 @@
|
||||
!!! 5
|
||||
html
|
||||
head
|
||||
title Search example
|
||||
style.
|
||||
body {
|
||||
font: 14px "Helvetica Neue", Helvetica;
|
||||
padding: 50px;
|
||||
}
|
||||
body
|
||||
h2 Search
|
||||
p Try searching for "ferret" or "cat".
|
||||
input(type='search')
|
||||
pre
|
||||
script(src='client.js')
|
||||
@@ -1,4 +1,8 @@
|
||||
|
||||
// first:
|
||||
// $ npm install redis
|
||||
// $ redis-server
|
||||
|
||||
var express = require('../..');
|
||||
|
||||
var app = express();
|
||||
@@ -25,4 +29,4 @@ app.get('/', function(req, res){
|
||||
});
|
||||
|
||||
app.listen(3000);
|
||||
console.log('Express app started on port 3000');
|
||||
console.log('Express app started on port 3000');
|
||||
|
||||
@@ -0,0 +1,44 @@
|
||||
|
||||
var express = require('../..');
|
||||
var app = express();
|
||||
|
||||
// log requests
|
||||
app.use(express.logger('dev'));
|
||||
|
||||
// express on its own has no notion
|
||||
// of a "file". The express.static()
|
||||
// middleware checks for a file matching
|
||||
// the `req.path` within the directory
|
||||
// that you pass it. In this case "GET /js/app.js"
|
||||
// will look for "./public/js/app.js".
|
||||
|
||||
app.use(express.static(__dirname + '/public'));
|
||||
|
||||
// if you wanted to "prefix" you may use
|
||||
// the mounting feature of Connect, for example
|
||||
// "GET /static/js/app.js" instead of "GET /js/app.js".
|
||||
// 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'));
|
||||
|
||||
// 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'));
|
||||
|
||||
// this examples does not have any routes, however
|
||||
// you may `app.use(app.router)` before or after these
|
||||
// static() middleware. If placed before them your routes
|
||||
// will be matched BEFORE file serving takes place. If placed
|
||||
// after as shown here then file serving is performed BEFORE
|
||||
// any routes are hit:
|
||||
app.use(app.router);
|
||||
|
||||
app.listen(3000);
|
||||
console.log('listening on port 3000');
|
||||
console.log('try:');
|
||||
console.log(' GET /hello.txt');
|
||||
console.log(' GET /js/app.js');
|
||||
console.log(' GET /css/style.css');
|
||||
@@ -0,0 +1,3 @@
|
||||
body {
|
||||
|
||||
}
|
||||
@@ -0,0 +1 @@
|
||||
hey
|
||||
@@ -0,0 +1 @@
|
||||
foo
|
||||
@@ -1,51 +0,0 @@
|
||||
|
||||
/**
|
||||
* Module dependencies.
|
||||
*/
|
||||
|
||||
var express = require('../../lib/express')
|
||||
, stylus = require('stylus');
|
||||
|
||||
var app = express.createServer();
|
||||
|
||||
// $ npm install stylus
|
||||
|
||||
// completely optional, however
|
||||
// the compile function allows you to
|
||||
// define additional functions exposed to Stylus,
|
||||
// alter settings, etc
|
||||
|
||||
function compile(str, path) {
|
||||
return stylus(str)
|
||||
.set('filename', path)
|
||||
.set('compress', true);
|
||||
};
|
||||
|
||||
// add the stylus middleware, which re-compiles when
|
||||
// a stylesheet has changed, compiling FROM src,
|
||||
// TO dest. dest is optional, defaulting to src
|
||||
|
||||
app.use(stylus.middleware({
|
||||
src: __dirname + '/views'
|
||||
, dest: __dirname + '/public'
|
||||
, compile: compile
|
||||
}));
|
||||
|
||||
|
||||
// minimal setup both reading and writting to ./public
|
||||
// would look like:
|
||||
// app.use(stylus.middleware({ src: __dirname + '/public' }));
|
||||
|
||||
// the middleware itself does not serve the static
|
||||
// css files, so we need to expose them with staticProvider
|
||||
|
||||
app.use(express.static(__dirname + '/public'));
|
||||
|
||||
app.set('views', __dirname + '/views');
|
||||
|
||||
app.get('/', function(req, res){
|
||||
res.render('index.jade');
|
||||
});
|
||||
|
||||
app.listen(3000);
|
||||
console.log('server listening on port 3000');
|
||||
@@ -1 +0,0 @@
|
||||
*.css
|
||||
@@ -1,2 +0,0 @@
|
||||
h1 Stylus
|
||||
p Just an example of using Stylus with Express.
|
||||
@@ -1,6 +0,0 @@
|
||||
html
|
||||
head
|
||||
title Stylus Example
|
||||
link(rel='stylesheet', href='/reset.css')
|
||||
link(rel='stylesheet', href='/main.css')
|
||||
body!= body
|
||||
@@ -1,8 +0,0 @@
|
||||
|
||||
body
|
||||
font 14px helvetica, arial, sans-serif
|
||||
padding 50px
|
||||
h1
|
||||
font-size 50px
|
||||
p
|
||||
margin 15px 0
|
||||
@@ -1,50 +0,0 @@
|
||||
|
||||
/**
|
||||
* Module dependencies.
|
||||
*/
|
||||
|
||||
var express = require('../../lib/express');
|
||||
|
||||
// Edit /etc/vhosts
|
||||
|
||||
// First app
|
||||
|
||||
var one = express.createServer();
|
||||
|
||||
one.use(express.logger());
|
||||
|
||||
one.get('/', function(req, res){
|
||||
res.send('Hello from app one!')
|
||||
});
|
||||
|
||||
one.get('/:sub', function(req, res){
|
||||
res.send('requsted ' + req.params.sub);
|
||||
});
|
||||
|
||||
// App two
|
||||
|
||||
var two = express.createServer();
|
||||
|
||||
two.get('/', function(req, res){
|
||||
res.send('Hello from app two!')
|
||||
});
|
||||
|
||||
// Redirect app
|
||||
|
||||
var redirect = express.createServer();
|
||||
|
||||
redirect.all('*', function(req, res){
|
||||
console.log(req.subdomains);
|
||||
res.redirect('http://localhost:3000/' + req.subdomains[0]);
|
||||
});
|
||||
|
||||
// Main app
|
||||
|
||||
var app = express.createServer();
|
||||
|
||||
app.use(express.vhost('*.localhost', redirect))
|
||||
app.use(express.vhost('localhost', one));
|
||||
app.use(express.vhost('dev', two));
|
||||
|
||||
app.listen(3000);
|
||||
console.log('Express app started on port 3000');
|
||||
@@ -0,0 +1,46 @@
|
||||
/**
|
||||
* Module dependencies.
|
||||
*/
|
||||
|
||||
var express = require('../..');
|
||||
|
||||
/*
|
||||
edit /etc/hosts:
|
||||
|
||||
127.0.0.1 foo.example.com
|
||||
127.0.0.1 bar.example.com
|
||||
127.0.0.1 example.com
|
||||
*/
|
||||
|
||||
// Main server app
|
||||
|
||||
var main = express();
|
||||
|
||||
main.use(express.logger('dev'));
|
||||
|
||||
main.get('/', function(req, res){
|
||||
res.send('Hello from main app!')
|
||||
});
|
||||
|
||||
main.get('/:sub', function(req, res){
|
||||
res.send('requested ' + req.params.sub);
|
||||
});
|
||||
|
||||
// Redirect app
|
||||
|
||||
var redirect = express();
|
||||
|
||||
redirect.all('*', function(req, res){
|
||||
console.log(req.subdomains);
|
||||
res.redirect('http://example.com:3000/' + req.subdomains[0]);
|
||||
});
|
||||
|
||||
// Vhost app
|
||||
|
||||
var app = express();
|
||||
|
||||
app.use(express.vhost('*.example.com', redirect)) // Serves all subdomains via Redirect app
|
||||
app.use(express.vhost('example.com', main)); // Serves top level domain via Main server app
|
||||
|
||||
app.listen(3000);
|
||||
console.log('Express app started on port 3000');
|
||||
@@ -0,0 +1,52 @@
|
||||
|
||||
/**
|
||||
* Module dependencies.
|
||||
*/
|
||||
|
||||
var http = require('http')
|
||||
, path = require('path')
|
||||
, extname = path.extname
|
||||
|
||||
/**
|
||||
* Expose `GithubView`.
|
||||
*/
|
||||
|
||||
module.exports = GithubView;
|
||||
|
||||
/**
|
||||
* Custom view that fetches and renders
|
||||
* remove github templates. You could
|
||||
* render templates from a database etc.
|
||||
*/
|
||||
|
||||
function GithubView(name, options){
|
||||
this.name = name;
|
||||
options = options || {};
|
||||
this.engine = options.engines[extname(name)];
|
||||
// "root" is the app.set('views') setting, however
|
||||
// in your own implementation you could ignore this
|
||||
this.path = '/' + options.root + '/master/' + name;
|
||||
}
|
||||
|
||||
/**
|
||||
* Render the view.
|
||||
*/
|
||||
|
||||
GithubView.prototype.render = function(options, fn){
|
||||
var self = this;
|
||||
var opts = {
|
||||
host: 'rawgithub.com',
|
||||
port: 80,
|
||||
path: this.path,
|
||||
method: 'GET'
|
||||
};
|
||||
|
||||
http.request(opts, function(res) {
|
||||
var buf = '';
|
||||
res.setEncoding('utf8');
|
||||
res.on('data', function(str){ buf += str });
|
||||
res.on('end', function(){
|
||||
self.engine(buf, options, fn);
|
||||
});
|
||||
}).end();
|
||||
};
|
||||
@@ -0,0 +1,47 @@
|
||||
|
||||
/**
|
||||
* Module dependencies.
|
||||
*/
|
||||
|
||||
var express = require('../../')
|
||||
, http = require('http')
|
||||
, GithubView = require('./github-view')
|
||||
, md = require('marked').parse;
|
||||
|
||||
var app = module.exports = express();
|
||||
|
||||
// register .md as an engine in express view system
|
||||
app.engine('md', function(str, options, fn){
|
||||
try {
|
||||
var html = md(str);
|
||||
html = html.replace(/\{([^}]+)\}/g, function(_, name){
|
||||
return options[name] || '';
|
||||
})
|
||||
fn(null, html);
|
||||
} catch(err) {
|
||||
fn(err);
|
||||
}
|
||||
})
|
||||
|
||||
// pointing to a particular github repo to load files from it
|
||||
app.set('views', 'visionmedia/express');
|
||||
|
||||
// register a new view constructor
|
||||
app.set('view', GithubView);
|
||||
|
||||
app.get('/', function(req, res){
|
||||
// rendering a view relative to the repo.
|
||||
// app.locals, res.locals, and locals passed
|
||||
// work like they normally would
|
||||
res.render('examples/markdown/views/index.md', { title: 'Example' });
|
||||
})
|
||||
|
||||
app.get('/Readme.md', function(req, res){
|
||||
// rendering a view from https://github.com/visionmedia/express/blob/master/Readme.md
|
||||
res.render('Readme.md');
|
||||
})
|
||||
|
||||
if (!module.parent) {
|
||||
app.listen(3000);
|
||||
console.log('Express started on port 3000');
|
||||
}
|
||||
@@ -101,10 +101,46 @@ app.get('/middleware-locals', count2, users2, function(req, res, next){
|
||||
res.render('user', { title: 'Users' });
|
||||
});
|
||||
|
||||
// keep in mind that middleware may be placed anywhere
|
||||
// and in various combinations, so if you have locals
|
||||
// that you wish to make available to all subsequent
|
||||
// middleware/routes you can do something like this:
|
||||
|
||||
app.get('/locals', function(req, res){
|
||||
res.render('user', { title: 'Users' });
|
||||
/*
|
||||
|
||||
app.use(function(req, res, next){
|
||||
res.locals.user = req.user;
|
||||
res.locals.sess = req.session;
|
||||
next();
|
||||
});
|
||||
|
||||
*/
|
||||
|
||||
// or suppose you have some /admin
|
||||
// "global" local variables:
|
||||
|
||||
/*
|
||||
|
||||
app.use('/api', function(req, res, next){
|
||||
res.locals.user = req.user;
|
||||
res.locals.sess = req.session;
|
||||
next();
|
||||
});
|
||||
|
||||
*/
|
||||
|
||||
// the following is effectively the same,
|
||||
// but uses a route instead:
|
||||
|
||||
/*
|
||||
|
||||
app.all('/api/*', function(req, res, next){
|
||||
res.locals.user = req.user;
|
||||
res.locals.sess = req.session;
|
||||
next();
|
||||
});
|
||||
|
||||
*/
|
||||
|
||||
app.listen(3000);
|
||||
console.log('Application listening on port 3000');
|
||||
@@ -2,7 +2,7 @@ doctype 5
|
||||
html
|
||||
head
|
||||
title= title
|
||||
style
|
||||
style.
|
||||
body {
|
||||
padding: 50px;
|
||||
font: 16px Helvetica, Arial;
|
||||
|
||||
+53
-34
@@ -9,12 +9,8 @@ var connect = require('connect')
|
||||
, debug = require('debug')('express:application')
|
||||
, locals = require('./utils').locals
|
||||
, View = require('./view')
|
||||
, url = require('url')
|
||||
, utils = connect.utils
|
||||
, path = require('path')
|
||||
, http = require('http')
|
||||
, join = path.join
|
||||
, fs = require('fs');
|
||||
, http = require('http');
|
||||
|
||||
/**
|
||||
* Application prototype.
|
||||
@@ -33,11 +29,9 @@ var app = exports = module.exports = {};
|
||||
*/
|
||||
|
||||
app.init = function(){
|
||||
var self = this;
|
||||
this.cache = {};
|
||||
this.settings = {};
|
||||
this.engines = {};
|
||||
this.viewCallbacks = [];
|
||||
this.defaultConfiguration();
|
||||
};
|
||||
|
||||
@@ -48,10 +42,11 @@ app.init = function(){
|
||||
*/
|
||||
|
||||
app.defaultConfiguration = function(){
|
||||
var self = this;
|
||||
|
||||
// default settings
|
||||
this.enable('x-powered-by');
|
||||
this.enable('etag');
|
||||
this.set('env', process.env.NODE_ENV || 'development');
|
||||
this.set('subdomain offset', 2);
|
||||
debug('booting in %s mode', this.get('env'));
|
||||
|
||||
// implicit middleware
|
||||
@@ -63,6 +58,7 @@ app.defaultConfiguration = function(){
|
||||
this.request.__proto__ = parent.request;
|
||||
this.response.__proto__ = parent.response;
|
||||
this.engines.__proto__ = parent.engines;
|
||||
this.settings.__proto__ = parent.settings;
|
||||
});
|
||||
|
||||
// router
|
||||
@@ -82,7 +78,8 @@ app.defaultConfiguration = function(){
|
||||
this.locals.settings = this.settings;
|
||||
|
||||
// default configuration
|
||||
this.enable('jsonp callback');
|
||||
this.set('view', View);
|
||||
this.set('views', process.cwd() + '/views');
|
||||
this.set('jsonp callback name', 'callback');
|
||||
|
||||
this.configure('development', function(){
|
||||
@@ -105,7 +102,7 @@ app.defaultConfiguration = function(){
|
||||
*/
|
||||
|
||||
app.use = function(route, fn){
|
||||
var app, home, handle;
|
||||
var app;
|
||||
|
||||
// default route to '/'
|
||||
if ('string' != typeof route) fn = route, route = '/';
|
||||
@@ -119,7 +116,6 @@ app.use = function(route, fn){
|
||||
fn = function(req, res, next) {
|
||||
var orig = req.app;
|
||||
app.handle(req, res, function(err){
|
||||
req.app = res.app = orig;
|
||||
req.__proto__ = orig.request;
|
||||
res.__proto__ = orig.response;
|
||||
next(err);
|
||||
@@ -164,7 +160,7 @@ app.use = function(route, fn){
|
||||
* [Consolidate.js](https://github.com/visionmedia/consolidate.js)
|
||||
* library was created to map all of node's popular template
|
||||
* engines to follow this convention, thus allowing them to
|
||||
* work seemlessly within Express.
|
||||
* work seamlessly within Express.
|
||||
*
|
||||
* @param {String} ext
|
||||
* @param {Function} fn
|
||||
@@ -187,7 +183,7 @@ app.engine = function(ext, fn){
|
||||
* could automatically load a user's information from the database without
|
||||
* any additional code,
|
||||
*
|
||||
* The callback uses the samesignature as middleware, the only differencing
|
||||
* The callback uses the same signature as middleware, the only difference
|
||||
* being that the value of the placeholder is passed, in this case the _id_
|
||||
* of the user. Once the `next()` function is invoked, just like middleware
|
||||
* it will continue on to execute the route, or subsequent parameter functions.
|
||||
@@ -253,11 +249,7 @@ app.param = function(name, fn){
|
||||
|
||||
app.set = function(setting, val){
|
||||
if (1 == arguments.length) {
|
||||
if (this.settings.hasOwnProperty(setting)) {
|
||||
return this.settings[setting];
|
||||
} else if (this.parent) {
|
||||
return this.parent.set(setting);
|
||||
}
|
||||
return this.settings[setting];
|
||||
} else {
|
||||
this.settings[setting] = val;
|
||||
return this;
|
||||
@@ -401,16 +393,25 @@ app.configure = function(env, fn){
|
||||
};
|
||||
|
||||
/**
|
||||
* Delegate `.VERB(...)` calls to `.route(VERB, ...)`.
|
||||
* Delegate `.VERB(...)` calls to `router.VERB(...)`.
|
||||
*/
|
||||
|
||||
methods.forEach(function(method){
|
||||
app[method] = function(path){
|
||||
if ('get' == method && 1 == arguments.length) return this.set(path);
|
||||
var args = [method].concat([].slice.call(arguments));
|
||||
if ('get' == method && 1 == arguments.length) return this.set(path);
|
||||
|
||||
// deprecated
|
||||
if (Array.isArray(path)) {
|
||||
console.trace('passing an array to app.VERB() is deprecated and will be removed in 4.0');
|
||||
}
|
||||
|
||||
// if no router attached yet, attach the router
|
||||
if (!this._usedRouter) this.use(this.router);
|
||||
return this._router.route.apply(this._router, args);
|
||||
}
|
||||
|
||||
// setup route
|
||||
this._router[method].apply(this._router, arguments);
|
||||
return this;
|
||||
};
|
||||
});
|
||||
|
||||
/**
|
||||
@@ -453,8 +454,7 @@ app.del = app.delete;
|
||||
*/
|
||||
|
||||
app.render = function(name, options, fn){
|
||||
var self = this
|
||||
, opts = {}
|
||||
var opts = {}
|
||||
, cache = this.cache
|
||||
, engines = this.engines
|
||||
, view;
|
||||
@@ -467,8 +467,8 @@ app.render = function(name, options, fn){
|
||||
// merge app.locals
|
||||
utils.merge(opts, this.locals);
|
||||
|
||||
// merge options.locals
|
||||
if (options.locals) utils.merge(opts, options.locals);
|
||||
// merge options._locals
|
||||
if (options._locals) utils.merge(opts, options._locals);
|
||||
|
||||
// merge options
|
||||
utils.merge(opts, options);
|
||||
@@ -483,10 +483,10 @@ app.render = function(name, options, fn){
|
||||
|
||||
// view
|
||||
if (!view) {
|
||||
view = new View(name, {
|
||||
defaultEngine: this.get('view engine')
|
||||
, root: this.get('views') || process.cwd() + '/views'
|
||||
, engines: engines
|
||||
view = new (this.get('view'))(name, {
|
||||
defaultEngine: this.get('view engine'),
|
||||
root: this.get('views'),
|
||||
engines: engines
|
||||
});
|
||||
|
||||
if (!view.path) {
|
||||
@@ -501,7 +501,26 @@ app.render = function(name, options, fn){
|
||||
|
||||
// render
|
||||
try {
|
||||
view.render(opts, fn);
|
||||
var view_stream = view.render(opts, fn);
|
||||
|
||||
// if the engine returned a stream AND user specified a function
|
||||
// then we will capture data for user
|
||||
if (view_stream && fn) {
|
||||
var body = '';
|
||||
view_stream.on('data', function(chunk) {
|
||||
body += chunk;
|
||||
});
|
||||
|
||||
view_stream.once('error', function(err) {
|
||||
fn(err);
|
||||
});
|
||||
|
||||
view_stream.once('end', function() {
|
||||
fn(null, body);
|
||||
});
|
||||
}
|
||||
|
||||
return view_stream;
|
||||
} catch (err) {
|
||||
fn(err);
|
||||
}
|
||||
@@ -522,7 +541,7 @@ app.render = function(name, options, fn){
|
||||
* , app = express();
|
||||
*
|
||||
* http.createServer(app).listen(80);
|
||||
* http.createServer({ ... }, app).listen(443);
|
||||
* https.createServer({ ... }, app).listen(443);
|
||||
*
|
||||
* @return {http.Server}
|
||||
* @api public
|
||||
|
||||
+16
-16
@@ -1,16 +1,13 @@
|
||||
|
||||
/**
|
||||
* Module dependencies.
|
||||
*/
|
||||
|
||||
var http = require('http')
|
||||
, connect = require('connect')
|
||||
var connect = require('connect')
|
||||
, proto = require('./application')
|
||||
, Route = require('./router/route')
|
||||
, Router = require('./router')
|
||||
, req = require('./request')
|
||||
, res = require('./response')
|
||||
, send = require('send')
|
||||
, utils = connect.utils;
|
||||
|
||||
/**
|
||||
@@ -19,17 +16,11 @@ var http = require('http')
|
||||
|
||||
exports = module.exports = createApplication;
|
||||
|
||||
/**
|
||||
* Framework version.
|
||||
*/
|
||||
|
||||
exports.version = '3.0.0beta7';
|
||||
|
||||
/**
|
||||
* Expose mime.
|
||||
*/
|
||||
|
||||
exports.mime = send.mime;
|
||||
exports.mime = connect.mime;
|
||||
|
||||
/**
|
||||
* Create an express application.
|
||||
@@ -41,15 +32,15 @@ exports.mime = send.mime;
|
||||
function createApplication() {
|
||||
var app = connect();
|
||||
utils.merge(app, proto);
|
||||
app.request = { __proto__: req };
|
||||
app.response = { __proto__: res };
|
||||
app.request = { __proto__: req, app: app };
|
||||
app.response = { __proto__: res, app: app };
|
||||
app.init();
|
||||
return app;
|
||||
}
|
||||
|
||||
/**
|
||||
* Expose connect.middleware as express.*
|
||||
* for example `express.logger` etc.
|
||||
* for example `express.logger` etc.
|
||||
*/
|
||||
|
||||
for (var key in connect.middleware) {
|
||||
@@ -60,10 +51,19 @@ for (var key in connect.middleware) {
|
||||
}
|
||||
|
||||
/**
|
||||
* Backwards compat.
|
||||
* Error on createServer().
|
||||
*/
|
||||
|
||||
exports.createServer = createApplication;
|
||||
exports.createServer = function(){
|
||||
console.warn('Warning: express.createServer() is deprecated, express');
|
||||
console.warn('applications no longer inherit from http.Server,');
|
||||
console.warn('please use:');
|
||||
console.warn('');
|
||||
console.warn(' var express = require("express");');
|
||||
console.warn(' var app = express();');
|
||||
console.warn('');
|
||||
return createApplication();
|
||||
};
|
||||
|
||||
/**
|
||||
* Expose the prototypes.
|
||||
|
||||
+1
-2
@@ -17,8 +17,7 @@ var utils = require('./utils');
|
||||
|
||||
exports.init = function(app){
|
||||
return function expressInit(req, res, next){
|
||||
req.app = res.app = app;
|
||||
res.setHeader('X-Powered-By', 'Express');
|
||||
if (app.enabled('x-powered-by')) res.setHeader('X-Powered-By', 'Express');
|
||||
req.res = res;
|
||||
res.req = req;
|
||||
req.next = next;
|
||||
|
||||
+78
-33
@@ -29,21 +29,21 @@ var req = exports = module.exports = {
|
||||
*
|
||||
* req.get('Content-Type');
|
||||
* // => "text/plain"
|
||||
*
|
||||
*
|
||||
* req.get('content-type');
|
||||
* // => "text/plain"
|
||||
*
|
||||
*
|
||||
* req.get('Something');
|
||||
* // => undefined
|
||||
*
|
||||
* Aliased as `req.header()`.
|
||||
*
|
||||
* @param {String} name
|
||||
* @return {String}
|
||||
* @return {String}
|
||||
* @api public
|
||||
*/
|
||||
|
||||
req.get =
|
||||
req.get =
|
||||
req.header = function(name){
|
||||
switch (name = name.toLowerCase()) {
|
||||
case 'referer':
|
||||
@@ -63,11 +63,12 @@ req.header = function(name){
|
||||
* The `type` value may be a single mime type string
|
||||
* such as "application/json", the extension name
|
||||
* such as "json", a comma-delimted list such as "json, html, text/plain",
|
||||
* an argument list such as `"json", "html", "text/plain"`,
|
||||
* or an array `["json", "html", "text/plain"]`. When a list
|
||||
* or array is given the _best_ match, if any is returned.
|
||||
*
|
||||
* Examples:
|
||||
*
|
||||
*
|
||||
* // Accept: text/html
|
||||
* req.accepts('html');
|
||||
* // => "html"
|
||||
@@ -89,6 +90,7 @@ req.header = function(name){
|
||||
*
|
||||
* // Accept: text/*;q=.5, application/json
|
||||
* req.accepts(['html', 'json']);
|
||||
* req.accepts('html', 'json');
|
||||
* req.accepts('html, json');
|
||||
* // => "json"
|
||||
*
|
||||
@@ -98,7 +100,20 @@ req.header = function(name){
|
||||
*/
|
||||
|
||||
req.accepts = function(type){
|
||||
return utils.accepts(type, this.get('Accept'));
|
||||
var args = arguments.length > 1 ? [].slice.apply(arguments) : type;
|
||||
return utils.accepts(args, this.get('Accept'));
|
||||
};
|
||||
|
||||
/**
|
||||
* Check if the given `encoding` is accepted.
|
||||
*
|
||||
* @param {String} encoding
|
||||
* @return {Boolean}
|
||||
* @api public
|
||||
*/
|
||||
|
||||
req.acceptsEncoding = function(encoding){
|
||||
return !! ~this.acceptedEncodings.indexOf(encoding);
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -113,7 +128,7 @@ req.accepts = function(type){
|
||||
req.acceptsCharset = function(charset){
|
||||
var accepted = this.acceptedCharsets;
|
||||
return accepted.length
|
||||
? ~accepted.indexOf(charset)
|
||||
? !! ~accepted.indexOf(charset)
|
||||
: true;
|
||||
};
|
||||
|
||||
@@ -129,7 +144,7 @@ req.acceptsCharset = function(charset){
|
||||
req.acceptsLanguage = function(lang){
|
||||
var accepted = this.acceptedLanguages;
|
||||
return accepted.length
|
||||
? ~accepted.indexOf(lang)
|
||||
? !! ~accepted.indexOf(lang)
|
||||
: true;
|
||||
};
|
||||
|
||||
@@ -159,6 +174,24 @@ req.range = function(size){
|
||||
return parseRange(size, range);
|
||||
};
|
||||
|
||||
/**
|
||||
* Return an array of encodings.
|
||||
*
|
||||
* Examples:
|
||||
*
|
||||
* ['gzip', 'deflate']
|
||||
*
|
||||
* @return {Array}
|
||||
* @api public
|
||||
*/
|
||||
|
||||
req.__defineGetter__('acceptedEncodings', function(){
|
||||
var accept = this.get('Accept-Encoding');
|
||||
return accept
|
||||
? accept.trim().split(/ *, */)
|
||||
: [];
|
||||
});
|
||||
|
||||
/**
|
||||
* Return an array of Accepted media types
|
||||
* ordered from highest quality to lowest.
|
||||
@@ -202,7 +235,7 @@ req.__defineGetter__('acceptedLanguages', function(){
|
||||
var accept = this.get('Accept-Language');
|
||||
return accept
|
||||
? utils
|
||||
.parseQuality(accept)
|
||||
.parseParams(accept)
|
||||
.map(function(obj){
|
||||
return obj.value;
|
||||
})
|
||||
@@ -226,7 +259,7 @@ req.__defineGetter__('acceptedCharsets', function(){
|
||||
var accept = this.get('Accept-Charset');
|
||||
return accept
|
||||
? utils
|
||||
.parseQuality(accept)
|
||||
.parseParams(accept)
|
||||
.map(function(obj){
|
||||
return obj.value;
|
||||
})
|
||||
@@ -245,7 +278,7 @@ req.__defineGetter__('acceptedCharsets', function(){
|
||||
* the `connect.bodyParser()` middleware.
|
||||
*
|
||||
* @param {String} name
|
||||
* @param {Mixed} defaultValue
|
||||
* @param {Mixed} [defaultValue]
|
||||
* @return {String}
|
||||
* @api public
|
||||
*/
|
||||
@@ -261,7 +294,7 @@ req.param = function(name, defaultValue){
|
||||
};
|
||||
|
||||
/**
|
||||
* Check if the incoming request contains the "Content-Type"
|
||||
* Check if the incoming request contains the "Content-Type"
|
||||
* header field, and it contains the give mime `type`.
|
||||
*
|
||||
* Examples:
|
||||
@@ -271,16 +304,16 @@ req.param = function(name, defaultValue){
|
||||
* req.is('text/html');
|
||||
* req.is('text/*');
|
||||
* // => true
|
||||
*
|
||||
*
|
||||
* // When Content-Type is application/json
|
||||
* req.is('json');
|
||||
* req.is('application/json');
|
||||
* req.is('application/*');
|
||||
* // => true
|
||||
*
|
||||
*
|
||||
* req.is('html');
|
||||
* // => false
|
||||
*
|
||||
*
|
||||
* @param {String} type
|
||||
* @return {Boolean}
|
||||
* @api public
|
||||
@@ -303,7 +336,7 @@ req.is = function(type){
|
||||
|
||||
/**
|
||||
* Return the protocol string "http" or "https"
|
||||
* when requested with TLS. When the "trust proxy"
|
||||
* when requested with TLS. When the "trust proxy"
|
||||
* setting is enabled the "X-Forwarded-Proto" header
|
||||
* field will be trusted. If you're running behind
|
||||
* a reverse proxy that supplies https for you this
|
||||
@@ -315,11 +348,10 @@ req.is = function(type){
|
||||
|
||||
req.__defineGetter__('protocol', function(){
|
||||
var trustProxy = this.app.get('trust proxy');
|
||||
return this.connection.encrypted
|
||||
? 'https'
|
||||
: trustProxy
|
||||
? (this.get('X-Forwarded-Proto') || 'http')
|
||||
: 'http';
|
||||
if (this.connection.encrypted) return 'https';
|
||||
if (!trustProxy) return 'http';
|
||||
var proto = this.get('X-Forwarded-Proto') || 'http';
|
||||
return proto.split(/\s*,\s*/)[0];
|
||||
});
|
||||
|
||||
/**
|
||||
@@ -377,39 +409,48 @@ req.__defineGetter__('ips', function(){
|
||||
* req.auth
|
||||
* // => { username: 'tobi', password: 'hello' }
|
||||
*
|
||||
* @return {Object}
|
||||
* @return {Object} or undefined
|
||||
* @api public
|
||||
*/
|
||||
|
||||
req.__defineGetter__('auth', function(){
|
||||
// missing
|
||||
var auth = this.get('Authorization');
|
||||
if (!auth) return {};
|
||||
if (!auth) return;
|
||||
|
||||
// malformed
|
||||
auth = auth.split(' ')[1];
|
||||
if (!auth) return {};
|
||||
var parts = auth.split(' ');
|
||||
if ('basic' != parts[0].toLowerCase()) return;
|
||||
if (!parts[1]) return;
|
||||
auth = parts[1];
|
||||
|
||||
// credentials
|
||||
auth = new Buffer(auth, 'base64').toString().split(':');
|
||||
return { username: auth[0], password: auth[1] };
|
||||
auth = new Buffer(auth, 'base64').toString().match(/^([^:]*):(.*)$/);
|
||||
if (!auth) return;
|
||||
return { username: auth[1], password: auth[2] };
|
||||
});
|
||||
|
||||
/**
|
||||
* Return subdomains as an array.
|
||||
*
|
||||
* For example "tobi.ferrets.example.com"
|
||||
* would provide `["ferrets", "tobi"]`.
|
||||
* Subdomains are the dot-separated parts of the host before the main domain of
|
||||
* the app. By default, the domain of the app is assumed to be the last two
|
||||
* parts of the host. This can be changed by setting "subdomain offset".
|
||||
*
|
||||
* For example, if the domain is "tobi.ferrets.example.com":
|
||||
* If "subdomain offset" is not set, req.subdomains is `["ferrets", "tobi"]`.
|
||||
* If "subdomain offset" is 3, req.subdomains is `["tobi"]`.
|
||||
*
|
||||
* @return {Array}
|
||||
* @api public
|
||||
*/
|
||||
|
||||
req.__defineGetter__('subdomains', function(){
|
||||
return this.get('Host')
|
||||
var offset = this.app.get('subdomain offset');
|
||||
return (this.host || '')
|
||||
.split('.')
|
||||
.slice(0, -2)
|
||||
.reverse();
|
||||
.reverse()
|
||||
.slice(offset);
|
||||
});
|
||||
|
||||
/**
|
||||
@@ -431,7 +472,11 @@ req.__defineGetter__('path', function(){
|
||||
*/
|
||||
|
||||
req.__defineGetter__('host', function(){
|
||||
return this.get('Host').split(':')[0];
|
||||
var trustProxy = this.app.get('trust proxy');
|
||||
var host = trustProxy && this.get('X-Forwarded-Host');
|
||||
host = host || this.get('Host');
|
||||
if (!host) return;
|
||||
return host.split(':')[0];
|
||||
});
|
||||
|
||||
/**
|
||||
|
||||
+323
-85
@@ -2,21 +2,21 @@
|
||||
* Module dependencies.
|
||||
*/
|
||||
|
||||
var fs = require('fs')
|
||||
, http = require('http')
|
||||
var http = require('http')
|
||||
, path = require('path')
|
||||
, connect = require('connect')
|
||||
, utils = connect.utils
|
||||
, sign = require('cookie-signature').sign
|
||||
, normalizeType = require('./utils').normalizeType
|
||||
, normalizeTypes = require('./utils').normalizeTypes
|
||||
, etag = require('./utils').etag
|
||||
, statusCodes = http.STATUS_CODES
|
||||
, send = connect.static.send
|
||||
, cookie = require('cookie')
|
||||
, send = require('send')
|
||||
, mime = connect.mime
|
||||
, resolve = require('url').resolve
|
||||
, basename = path.basename
|
||||
, extname = path.extname
|
||||
, join = path.join;
|
||||
, extname = path.extname;
|
||||
|
||||
/**
|
||||
* Response prototype.
|
||||
@@ -55,7 +55,9 @@ res.status = function(code){
|
||||
*/
|
||||
|
||||
res.links = function(links){
|
||||
return this.set('Link', Object.keys(links).map(function(rel){
|
||||
var link = this.get('Link') || '';
|
||||
if (link) link += ', ';
|
||||
return this.set('Link', link + Object.keys(links).map(function(rel){
|
||||
return '<' + links[rel] + '>; rel="' + rel + '"';
|
||||
}).join(', '));
|
||||
};
|
||||
@@ -77,7 +79,81 @@ res.links = function(links){
|
||||
* @api public
|
||||
*/
|
||||
|
||||
res.send = require('response-send');
|
||||
res.send = function(body){
|
||||
var req = this.req;
|
||||
var head = 'HEAD' == req.method;
|
||||
var len;
|
||||
|
||||
// settings
|
||||
var app = this.app;
|
||||
|
||||
// allow status / body
|
||||
if (2 == arguments.length) {
|
||||
// res.send(body, status) backwards compat
|
||||
if ('number' != typeof body && 'number' == typeof arguments[1]) {
|
||||
this.statusCode = arguments[1];
|
||||
} else {
|
||||
this.statusCode = body;
|
||||
body = arguments[1];
|
||||
}
|
||||
}
|
||||
|
||||
switch (typeof body) {
|
||||
// response status
|
||||
case 'number':
|
||||
this.get('Content-Type') || this.type('txt');
|
||||
this.statusCode = body;
|
||||
body = http.STATUS_CODES[body];
|
||||
break;
|
||||
// string defaulting to html
|
||||
case 'string':
|
||||
if (!this.get('Content-Type')) {
|
||||
this.charset = this.charset || 'utf-8';
|
||||
this.type('html');
|
||||
}
|
||||
break;
|
||||
case 'boolean':
|
||||
case 'object':
|
||||
if (null == body) {
|
||||
body = '';
|
||||
} else if (Buffer.isBuffer(body)) {
|
||||
this.get('Content-Type') || this.type('bin');
|
||||
} else {
|
||||
return this.json(body);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
// populate Content-Length
|
||||
if (undefined !== body && !this.get('Content-Length')) {
|
||||
this.set('Content-Length', len = Buffer.isBuffer(body)
|
||||
? body.length
|
||||
: Buffer.byteLength(body));
|
||||
}
|
||||
|
||||
// ETag support
|
||||
// TODO: W/ support
|
||||
if (app.settings.etag && len && 'GET' == req.method) {
|
||||
if (!this.get('ETag')) {
|
||||
this.set('ETag', etag(body));
|
||||
}
|
||||
}
|
||||
|
||||
// freshness
|
||||
if (req.fresh) this.statusCode = 304;
|
||||
|
||||
// strip irrelevant headers
|
||||
if (204 == this.statusCode || 304 == this.statusCode) {
|
||||
this.removeHeader('Content-Type');
|
||||
this.removeHeader('Content-Length');
|
||||
this.removeHeader('Transfer-Encoding');
|
||||
body = '';
|
||||
}
|
||||
|
||||
// respond
|
||||
this.end(head ? null : body);
|
||||
return this;
|
||||
};
|
||||
|
||||
/**
|
||||
* Send JSON response.
|
||||
@@ -108,21 +184,65 @@ res.json = function(obj){
|
||||
}
|
||||
|
||||
// settings
|
||||
var app = this.app
|
||||
, jsonp = app.get('jsonp callback')
|
||||
, replacer = app.get('json replacer')
|
||||
, spaces = app.get('json spaces')
|
||||
, body = JSON.stringify(obj, replacer, spaces)
|
||||
, callback = this.req.query[app.get('jsonp callback name')];
|
||||
var app = this.app;
|
||||
var replacer = app.get('json replacer');
|
||||
var spaces = app.get('json spaces');
|
||||
var body = JSON.stringify(obj, replacer, spaces);
|
||||
|
||||
// content-type
|
||||
this.charset = this.charset || 'utf-8';
|
||||
this.get('Content-Type') || this.set('Content-Type', 'application/json');
|
||||
|
||||
return this.send(body);
|
||||
};
|
||||
|
||||
/**
|
||||
* Send JSON response with JSONP callback support.
|
||||
*
|
||||
* Examples:
|
||||
*
|
||||
* res.jsonp(null);
|
||||
* res.jsonp({ user: 'tj' });
|
||||
* res.jsonp(500, 'oh noes!');
|
||||
* res.jsonp(404, 'I dont have that');
|
||||
*
|
||||
* @param {Mixed} obj or status
|
||||
* @param {Mixed} obj
|
||||
* @return {ServerResponse}
|
||||
* @api public
|
||||
*/
|
||||
|
||||
res.jsonp = function(obj){
|
||||
// allow status / body
|
||||
if (2 == arguments.length) {
|
||||
// res.json(body, status) backwards compat
|
||||
if ('number' == typeof arguments[1]) {
|
||||
this.statusCode = arguments[1];
|
||||
} else {
|
||||
this.statusCode = obj;
|
||||
obj = arguments[1];
|
||||
}
|
||||
}
|
||||
|
||||
// settings
|
||||
var app = this.app;
|
||||
var replacer = app.get('json replacer');
|
||||
var spaces = app.get('json spaces');
|
||||
var body = JSON.stringify(obj, replacer, spaces)
|
||||
.replace(/\u2028/g, '\\u2028')
|
||||
.replace(/\u2029/g, '\\u2029');
|
||||
var callback = this.req.query[app.get('jsonp callback name')];
|
||||
|
||||
// content-type
|
||||
this.charset = this.charset || 'utf-8';
|
||||
this.set('Content-Type', 'application/json');
|
||||
|
||||
|
||||
// jsonp
|
||||
if (callback && jsonp) {
|
||||
if (callback) {
|
||||
if (Array.isArray(callback)) callback = callback[0];
|
||||
this.set('Content-Type', 'text/javascript');
|
||||
body = callback.replace(/[^[]\w$.]/g, '') + '(' + body + ');';
|
||||
var cb = callback.replace(/[^\[\]\w$.]/g, '');
|
||||
body = 'typeof ' + cb + ' === \'function\' && ' + cb + '(' + body + ');';
|
||||
}
|
||||
|
||||
return this.send(body);
|
||||
@@ -130,7 +250,7 @@ res.json = function(obj){
|
||||
|
||||
/**
|
||||
* Transfer the file at the given `path`.
|
||||
*
|
||||
*
|
||||
* Automatically sets the _Content-Type_ response header field.
|
||||
* The callback `fn(err)` is invoked when the transfer is complete
|
||||
* or when an error occurs. Be sure to check `res.sentHeader`
|
||||
@@ -152,7 +272,7 @@ res.json = function(obj){
|
||||
* app.get('/user/:uid/photos/:file', function(req, res){
|
||||
* var uid = req.params.uid
|
||||
* , file = req.params.file;
|
||||
*
|
||||
*
|
||||
* req.user.mayViewFilesFrom(uid, function(yes){
|
||||
* if (yes) {
|
||||
* res.sendfile('/uploads/' + uid + '/' + file);
|
||||
@@ -190,7 +310,7 @@ res.sendfile = function(path, options, fn){
|
||||
done = true;
|
||||
|
||||
// clean up
|
||||
req.socket.removeListener('error', error);
|
||||
cleanup();
|
||||
if (!self.headerSent) self.removeHeader('Content-Disposition');
|
||||
|
||||
// callback available
|
||||
@@ -204,10 +324,15 @@ res.sendfile = function(path, options, fn){
|
||||
}
|
||||
|
||||
// streaming
|
||||
function stream() {
|
||||
function stream(stream) {
|
||||
if (done) return;
|
||||
cleanup();
|
||||
if (fn) stream.on('end', fn);
|
||||
}
|
||||
|
||||
// cleanup
|
||||
function cleanup() {
|
||||
req.socket.removeListener('error', error);
|
||||
if (fn) self.on('finish', fn);
|
||||
}
|
||||
|
||||
// transfer
|
||||
@@ -218,6 +343,7 @@ res.sendfile = function(path, options, fn){
|
||||
file.on('directory', next);
|
||||
file.on('stream', stream);
|
||||
file.pipe(this);
|
||||
this.on('finish', cleanup);
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -291,11 +417,11 @@ res.type = function(type){
|
||||
* 'text/plain': function(){
|
||||
* res.send('hey');
|
||||
* },
|
||||
*
|
||||
*
|
||||
* 'text/html': function(){
|
||||
* res.send('<p>hey</p>');
|
||||
* },
|
||||
*
|
||||
*
|
||||
* 'appliation/json': function(){
|
||||
* res.send({ message: 'hey' });
|
||||
* }
|
||||
@@ -308,11 +434,11 @@ res.type = function(type){
|
||||
* text: function(){
|
||||
* res.send('hey');
|
||||
* },
|
||||
*
|
||||
*
|
||||
* html: function(){
|
||||
* res.send('<p>hey</p>');
|
||||
* },
|
||||
*
|
||||
*
|
||||
* json: function(){
|
||||
* res.send({ message: 'hey' });
|
||||
* }
|
||||
@@ -330,26 +456,29 @@ res.type = function(type){
|
||||
*/
|
||||
|
||||
res.format = function(obj){
|
||||
var keys = Object.keys(obj)
|
||||
, req = this.req
|
||||
var req = this.req
|
||||
, next = req.next;
|
||||
|
||||
var fn = obj.default;
|
||||
if (fn) delete obj.default;
|
||||
var keys = Object.keys(obj);
|
||||
|
||||
var key = req.accepts(keys);
|
||||
|
||||
this.set('Vary', 'Accept');
|
||||
this.vary("Accept");
|
||||
|
||||
if (key) {
|
||||
this.set('Content-Type', normalizeType(key));
|
||||
var type = normalizeType(key).value;
|
||||
var charset = mime.charsets.lookup(type);
|
||||
if (charset) type += '; charset=' + charset;
|
||||
this.set('Content-Type', type);
|
||||
obj[key](req, this, next);
|
||||
} else if (fn) {
|
||||
fn();
|
||||
} else {
|
||||
var err = new Error('Not Acceptable');
|
||||
err.status = 406;
|
||||
err.types = normalizeTypes(keys);
|
||||
err.types = normalizeTypes(keys).map(function(o){ return o.value });
|
||||
next(err);
|
||||
}
|
||||
|
||||
@@ -378,24 +507,27 @@ res.attachment = function(filename){
|
||||
*
|
||||
* Examples:
|
||||
*
|
||||
* res.set('Foo', ['bar', 'baz']);
|
||||
* res.set('Accept', 'application/json');
|
||||
* res.set({ Accept: 'text/plain', 'X-API-Key': 'tobi' });
|
||||
*
|
||||
* Aliased as `res.header()`.
|
||||
* Aliased as `res.header()`.
|
||||
*
|
||||
* @param {String|Object} field
|
||||
* @param {String|Object|Array} field
|
||||
* @param {String} val
|
||||
* @return {ServerResponse} for chaining
|
||||
* @api public
|
||||
*/
|
||||
|
||||
res.set =
|
||||
res.set =
|
||||
res.header = function(field, val){
|
||||
if (2 == arguments.length) {
|
||||
this.setHeader(field, '' + val);
|
||||
if (Array.isArray(val)) val = val.map(String);
|
||||
else val = String(val);
|
||||
this.setHeader(field, val);
|
||||
} else {
|
||||
for (var key in field) {
|
||||
this.setHeader(key, '' + field[key]);
|
||||
this.set(key, field[key]);
|
||||
}
|
||||
}
|
||||
return this;
|
||||
@@ -453,21 +585,25 @@ res.clearCookie = function(name, options){
|
||||
*/
|
||||
|
||||
res.cookie = function(name, val, options){
|
||||
options = options || {};
|
||||
options = utils.merge({}, options);
|
||||
var secret = this.req.secret;
|
||||
var signed = options.signed;
|
||||
if (signed && !secret) throw new Error('connect.cookieParser("secret") required for signed cookies');
|
||||
if ('number' == typeof val) val = val.toString();
|
||||
if ('object' == typeof val) val = 'j:' + JSON.stringify(val);
|
||||
if (signed) val = utils.sign(val, secret);
|
||||
if ('maxAge' in options) options.expires = new Date(Date.now() + options.maxAge);
|
||||
if (signed) val = 's:' + sign(val, secret);
|
||||
if ('maxAge' in options) {
|
||||
options.expires = new Date(Date.now() + options.maxAge);
|
||||
options.maxAge /= 1000;
|
||||
}
|
||||
if (null == options.path) options.path = '/';
|
||||
this.set('Set-Cookie', cookie.serialize(name, String(val), options));
|
||||
return this;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Redirect to the given `url` with optional response `status`
|
||||
* defaulting to 302.
|
||||
* Set the location header to `url`.
|
||||
*
|
||||
* The given `url` can also be the name of a mapped url, for
|
||||
* example by default express supports "back" which redirects
|
||||
@@ -475,41 +611,31 @@ res.cookie = function(name, val, options){
|
||||
*
|
||||
* Examples:
|
||||
*
|
||||
* res.redirect('/foo/bar');
|
||||
* res.redirect('http://example.com');
|
||||
* res.redirect(301, 'http://example.com');
|
||||
* res.redirect('../login'); // /blog/post/1 -> /blog/login
|
||||
* res.location('/foo/bar').;
|
||||
* res.location('http://example.com');
|
||||
* res.location('../login'); // /blog/post/1 -> /blog/login
|
||||
*
|
||||
* Mounting:
|
||||
*
|
||||
* When an application is mounted, and `res.redirect()`
|
||||
* is given a path that does _not_ lead with "/". For
|
||||
* example suppose a "blog" app is mounted at "/blog",
|
||||
* the following redirect would result in "/blog/login":
|
||||
* When an application is mounted and `res.location()`
|
||||
* is given a path that does _not_ lead with "/" it becomes
|
||||
* relative to the mount-point. For example if the application
|
||||
* is mounted at "/blog", the following would become "/blog/login".
|
||||
*
|
||||
* res.redirect('login');
|
||||
* res.location('login');
|
||||
*
|
||||
* While the leading slash would result in a redirect to "/login":
|
||||
* While the leading slash would result in a location of "/login":
|
||||
*
|
||||
* res.redirect('/login');
|
||||
* res.location('/login');
|
||||
*
|
||||
* @param {String} url
|
||||
* @param {Number} code
|
||||
* @api public
|
||||
*/
|
||||
|
||||
res.redirect = function(url){
|
||||
res.location = function(url){
|
||||
var app = this.app
|
||||
, req = this.req
|
||||
, head = 'HEAD' == req.method
|
||||
, status = 302
|
||||
, body;
|
||||
|
||||
// allow status / url
|
||||
if (2 == arguments.length) {
|
||||
status = url;
|
||||
url = arguments[1];
|
||||
}
|
||||
, path;
|
||||
|
||||
// setup redirect map
|
||||
var map = { back: req.get('Referrer') || '/' };
|
||||
@@ -518,30 +644,73 @@ res.redirect = function(url){
|
||||
url = map[url] || url;
|
||||
|
||||
// relative
|
||||
if (!~url.indexOf('://')) {
|
||||
var path = app.path();
|
||||
|
||||
if (!~url.indexOf('://') && 0 != url.indexOf('//')) {
|
||||
// relative to path
|
||||
if ('.' == url[0]) {
|
||||
url = req.path + '/' + url;
|
||||
// relative to mount-point
|
||||
path = req.originalUrl.split('?')[0];
|
||||
path = path + ('/' == path[path.length - 1] ? '' : '/');
|
||||
url = resolve(path, url);
|
||||
// relative to mount-point
|
||||
} else if ('/' != url[0]) {
|
||||
path = app.path();
|
||||
url = path + '/' + url;
|
||||
}
|
||||
|
||||
// Absolute
|
||||
var host = req.get('Host');
|
||||
url = req.protocol + '://' + host + url;
|
||||
}
|
||||
|
||||
// Respond
|
||||
this.set('Location', url);
|
||||
return this;
|
||||
};
|
||||
|
||||
/**
|
||||
* Redirect to the given `url` with optional response `status`
|
||||
* defaulting to 302.
|
||||
*
|
||||
* The resulting `url` is determined by `res.location()`, so
|
||||
* it will play nicely with mounted apps, relative paths,
|
||||
* `"back"` etc.
|
||||
*
|
||||
* Examples:
|
||||
*
|
||||
* res.redirect('/foo/bar');
|
||||
* res.redirect('http://example.com');
|
||||
* res.redirect(301, 'http://example.com');
|
||||
* res.redirect('http://example.com', 301);
|
||||
* res.redirect('../login'); // /blog/post/1 -> /blog/login
|
||||
*
|
||||
* @param {String} url
|
||||
* @param {Number} code
|
||||
* @api public
|
||||
*/
|
||||
|
||||
res.redirect = function(url){
|
||||
var head = 'HEAD' == this.req.method
|
||||
, status = 302
|
||||
, body;
|
||||
|
||||
// allow status / url
|
||||
if (2 == arguments.length) {
|
||||
if ('number' == typeof url) {
|
||||
status = url;
|
||||
url = arguments[1];
|
||||
} else {
|
||||
status = arguments[1];
|
||||
}
|
||||
}
|
||||
|
||||
// Set location header
|
||||
this.location(url);
|
||||
url = this.get('Location');
|
||||
|
||||
// Support text/{plain,html} by default
|
||||
this.format({
|
||||
text: function(){
|
||||
body = statusCodes[status] + '. Redirecting to ' + url;
|
||||
body = statusCodes[status] + '. Redirecting to ' + encodeURI(url);
|
||||
},
|
||||
|
||||
html: function(){
|
||||
body = '<p>' + statusCodes[status] + '. Redirecting to <a href="' + url + '">' + url + '</a></p>';
|
||||
var u = utils.escape(url);
|
||||
body = '<p>' + statusCodes[status] + '. Redirecting to <a href="' + u + '">' + u + '</a></p>';
|
||||
},
|
||||
|
||||
default: function(){
|
||||
@@ -551,22 +720,54 @@ res.redirect = function(url){
|
||||
|
||||
// Respond
|
||||
this.statusCode = status;
|
||||
this.set('Location', url);
|
||||
this.set('Content-Length', Buffer.byteLength(body));
|
||||
this.end(head ? null : body);
|
||||
};
|
||||
|
||||
/**
|
||||
* Add `field` to Vary. If already present in the Vary set, then
|
||||
* this call is simply ignored.
|
||||
*
|
||||
* @param {Array|String} field
|
||||
* @param {ServerResponse} for chaining
|
||||
* @api public
|
||||
*/
|
||||
|
||||
res.vary = function(field){
|
||||
var self = this;
|
||||
|
||||
// nothing
|
||||
if (!field) return this;
|
||||
|
||||
// array
|
||||
if (Array.isArray(field)) {
|
||||
field.forEach(function(field){
|
||||
self.vary(field);
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
var vary = this.get('Vary');
|
||||
|
||||
// append
|
||||
if (vary) {
|
||||
vary = vary.split(/ *, */);
|
||||
if (!~vary.indexOf(field)) vary.push(field);
|
||||
this.set('Vary', vary.join(', '));
|
||||
return this;
|
||||
}
|
||||
|
||||
// set
|
||||
this.set('Vary', field);
|
||||
return this;
|
||||
};
|
||||
|
||||
/**
|
||||
* Render `view` with the given `options` and optional callback `fn`.
|
||||
* When a callback function is given a response will _not_ be made
|
||||
* automatically, otherwise a response of _200_ and _text/html_ is given.
|
||||
*
|
||||
* Options:
|
||||
*
|
||||
* - `status` Response status code (`res.statusCode`)
|
||||
* - `charset` Set the charset (`res.charset`)
|
||||
*
|
||||
* Reserved locals:
|
||||
*
|
||||
* - `cache` boolean hinting to the engine it should cache
|
||||
* - `filename` filename of the view being rendered
|
||||
@@ -589,14 +790,51 @@ res.render = function(view, options, fn){
|
||||
}
|
||||
|
||||
// merge res.locals
|
||||
options.locals = self.locals;
|
||||
options._locals = self.locals;
|
||||
|
||||
// support for non streaming view rendering
|
||||
// if renderer uses streams, this will not be called
|
||||
// see below for how streams are handled
|
||||
var respond = fn || function(err, str){
|
||||
if (view_stream) return;
|
||||
|
||||
// default callback to respond
|
||||
fn = fn || function(err, str){
|
||||
if (err) return req.next(err);
|
||||
self.send(str);
|
||||
};
|
||||
|
||||
// render
|
||||
app.render(view, options, fn);
|
||||
};
|
||||
var view_stream = app.render(view, options, respond);
|
||||
|
||||
// old style, will have already called respond for us
|
||||
if (!view_stream) {
|
||||
return;
|
||||
}
|
||||
|
||||
// user wants to handle sending themselves
|
||||
if (fn) {
|
||||
var body = '';
|
||||
view_stream.on('data', function(chunk) {
|
||||
body += chunk;
|
||||
});
|
||||
|
||||
view_stream.once('error', function(err) {
|
||||
fn(err);
|
||||
});
|
||||
|
||||
view_stream.once('end', function() {
|
||||
fn(null, body);
|
||||
});
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
// set response headers
|
||||
self.statusCode = 200;
|
||||
if (!self.get('Content-Type')) {
|
||||
self.charset = self.charset || 'utf-8';
|
||||
self.type('html');
|
||||
}
|
||||
self.setHeader('Transfer-Encoding', 'chunked');
|
||||
|
||||
// start streaming the response
|
||||
view_stream.pipe(self);
|
||||
};
|
||||
|
||||
+25
-9
@@ -4,9 +4,9 @@
|
||||
|
||||
var Route = require('./route')
|
||||
, utils = require('../utils')
|
||||
, methods = require('methods')
|
||||
, debug = require('debug')('express:router')
|
||||
, parse = require('connect').utils.parseUrl
|
||||
, methods = require('methods');
|
||||
, parse = require('connect').utils.parseUrl;
|
||||
|
||||
/**
|
||||
* Expose `Router` constructor.
|
||||
@@ -16,7 +16,7 @@ exports = module.exports = Router;
|
||||
|
||||
/**
|
||||
* Initialize a new `Router` with the given `options`.
|
||||
*
|
||||
*
|
||||
* @param {Object} options
|
||||
* @api private
|
||||
*/
|
||||
@@ -93,8 +93,7 @@ Router.prototype._dispatch = function(req, res, next){
|
||||
, paramVal
|
||||
, route
|
||||
, keys
|
||||
, key
|
||||
, ret;
|
||||
, key;
|
||||
|
||||
// match next route
|
||||
function nextRoute(err) {
|
||||
@@ -144,7 +143,7 @@ Router.prototype._dispatch = function(req, res, next){
|
||||
};
|
||||
|
||||
param(err);
|
||||
|
||||
|
||||
// single param callbacks
|
||||
function paramCallback(err) {
|
||||
var fn = paramCallbacks[paramIndex++];
|
||||
@@ -162,7 +161,8 @@ Router.prototype._dispatch = function(req, res, next){
|
||||
if (fn.length < 4) return callbacks(err);
|
||||
fn(err, req, res, callbacks);
|
||||
} else if (fn) {
|
||||
fn(req, res, callbacks);
|
||||
if (fn.length < 4) return fn(req, res, callbacks);
|
||||
callbacks();
|
||||
} else {
|
||||
nextRoute(err);
|
||||
}
|
||||
@@ -282,14 +282,30 @@ Router.prototype.route = function(method, path, callbacks){
|
||||
// ensure path was given
|
||||
if (!path) throw new Error('Router#' + method + '() requires a path');
|
||||
|
||||
// ensure all callbacks are functions
|
||||
callbacks.forEach(function(fn){
|
||||
if ('function' == typeof fn) return;
|
||||
var type = {}.toString.call(fn);
|
||||
var msg = '.' + method + '() requires callback functions but got a ' + type;
|
||||
throw new Error(msg);
|
||||
});
|
||||
|
||||
// create the route
|
||||
debug('defined %s %s', method, path);
|
||||
var route = new Route(method, path, callbacks, {
|
||||
sensitive: this.caseSensitive
|
||||
, strict: this.strict
|
||||
sensitive: this.caseSensitive,
|
||||
strict: this.strict
|
||||
});
|
||||
|
||||
// add it
|
||||
(this.map[method] = this.map[method] || []).push(route);
|
||||
return this;
|
||||
};
|
||||
|
||||
methods.forEach(function(method){
|
||||
Router.prototype[method] = function(path){
|
||||
var args = [method].concat([].slice.call(arguments));
|
||||
this.route.apply(this, args);
|
||||
return this;
|
||||
};
|
||||
});
|
||||
|
||||
@@ -58,7 +58,7 @@ Route.prototype.match = function(path){
|
||||
var key = keys[i - 1];
|
||||
|
||||
var val = 'string' == typeof m[i]
|
||||
? decodeURIComponent(m[i])
|
||||
? utils.decode(m[i])
|
||||
: m[i];
|
||||
|
||||
if (key) {
|
||||
|
||||
+98
-34
@@ -3,21 +3,38 @@
|
||||
* Module dependencies.
|
||||
*/
|
||||
|
||||
var mime = require('connect').mime;
|
||||
var mime = require('connect').mime
|
||||
, crc32 = require('buffer-crc32');
|
||||
|
||||
/**
|
||||
* toString ref.
|
||||
*/
|
||||
|
||||
var toString = {}.toString;
|
||||
|
||||
/**
|
||||
* Return ETag for `body`.
|
||||
*
|
||||
* @param {String|Buffer} body
|
||||
* @return {String}
|
||||
* @api private
|
||||
*/
|
||||
|
||||
exports.etag = function(body){
|
||||
return '"' + crc32.signed(body) + '"';
|
||||
};
|
||||
|
||||
/**
|
||||
* Make `locals()` bound to the given `obj`.
|
||||
*
|
||||
* This is used for `app.locals` and `res.locals`.
|
||||
*
|
||||
* This is used for `app.locals` and `res.locals`.
|
||||
*
|
||||
* @param {Object} obj
|
||||
* @return {Function}
|
||||
* @api private
|
||||
*/
|
||||
|
||||
exports.locals = function(obj){
|
||||
obj.viewCallbacks = obj.viewCallbacks || [];
|
||||
|
||||
exports.locals = function(){
|
||||
function locals(obj){
|
||||
for (var key in obj) locals[key] = obj[key];
|
||||
return obj;
|
||||
@@ -37,6 +54,7 @@ exports.locals = function(obj){
|
||||
exports.isAbsolute = function(path){
|
||||
if ('/' == path[0]) return true;
|
||||
if (':' == path[1] && '\\' == path[2]) return true;
|
||||
if ('\\\\' == path.substring(0, 2)) return true; // Microsoft Azure absolute path
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -64,12 +82,14 @@ exports.flatten = function(arr, ret){
|
||||
* Normalize the given `type`, for example "html" becomes "text/html".
|
||||
*
|
||||
* @param {String} type
|
||||
* @return {String}
|
||||
* @return {Object}
|
||||
* @api private
|
||||
*/
|
||||
|
||||
exports.normalizeType = function(type){
|
||||
return ~type.indexOf('/') ? type : mime.lookup(type);
|
||||
return ~type.indexOf('/')
|
||||
? acceptParams(type)
|
||||
: { value: mime.lookup(type), params: {} };
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -84,9 +104,7 @@ exports.normalizeTypes = function(types){
|
||||
var ret = [];
|
||||
|
||||
for (var i = 0; i < types.length; ++i) {
|
||||
ret.push(~types[i].indexOf('/')
|
||||
? types[i]
|
||||
: mime.lookup(types[i]));
|
||||
ret.push(exports.normalizeType(types[i]));
|
||||
}
|
||||
|
||||
return ret;
|
||||
@@ -112,7 +130,7 @@ exports.acceptsArray = function(types, str){
|
||||
|
||||
for (var i = 0; i < len; ++i) {
|
||||
for (var j = 0, jlen = types.length; j < jlen; ++j) {
|
||||
if (exports.accept(normalized[j].split('/'), accepted[i])) {
|
||||
if (exports.accept(normalized[j], accepted[i])) {
|
||||
return types[j];
|
||||
}
|
||||
}
|
||||
@@ -137,17 +155,34 @@ exports.accepts = function(type, str){
|
||||
/**
|
||||
* Check if `type` array is acceptable for `other`.
|
||||
*
|
||||
* @param {Array} type
|
||||
* @param {Object} type
|
||||
* @param {Object} other
|
||||
* @return {Boolean}
|
||||
* @api private
|
||||
*/
|
||||
|
||||
exports.accept = function(type, other){
|
||||
return (type[0] == other.type || '*' == other.type)
|
||||
&& (type[1] == other.subtype || '*' == other.subtype);
|
||||
var t = type.value.split('/');
|
||||
return (t[0] == other.type || '*' == other.type)
|
||||
&& (t[1] == other.subtype || '*' == other.subtype)
|
||||
&& paramsEqual(type.params, other.params);
|
||||
};
|
||||
|
||||
/**
|
||||
* Check if accept params are equal.
|
||||
*
|
||||
* @param {Object} a
|
||||
* @param {Object} b
|
||||
* @return {Boolean}
|
||||
* @api private
|
||||
*/
|
||||
|
||||
function paramsEqual(a, b){
|
||||
return !Object.keys(a).some(function(k) {
|
||||
return a[k] != b[k];
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Parse accept `str`, returning
|
||||
* an array objects containing
|
||||
@@ -162,7 +197,7 @@ exports.accept = function(type, other){
|
||||
|
||||
exports.parseAccept = function(str){
|
||||
return exports
|
||||
.parseQuality(str)
|
||||
.parseParams(str)
|
||||
.map(function(obj){
|
||||
var parts = obj.value.split('/');
|
||||
obj.type = parts[0];
|
||||
@@ -173,44 +208,54 @@ exports.parseAccept = function(str){
|
||||
|
||||
/**
|
||||
* Parse quality `str`, returning an
|
||||
* array of objects with `.value` and
|
||||
* `.quality`.
|
||||
* array of objects with `.value`,
|
||||
* `.quality` and optional `.params`
|
||||
*
|
||||
* @param {Type} name
|
||||
* @return {Type}
|
||||
* @param {String} str
|
||||
* @return {Array}
|
||||
* @api private
|
||||
*/
|
||||
|
||||
exports.parseQuality = function(str){
|
||||
exports.parseParams = function(str){
|
||||
return str
|
||||
.split(/ *, */)
|
||||
.map(quality)
|
||||
.map(acceptParams)
|
||||
.filter(function(obj){
|
||||
return obj.quality;
|
||||
})
|
||||
.sort(function(a, b){
|
||||
return b.quality - a.quality;
|
||||
if (a.quality === b.quality) {
|
||||
return a.originalIndex - b.originalIndex;
|
||||
} else {
|
||||
return b.quality - a.quality;
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* Parse quality `str` returning an
|
||||
* object with `.value` and `.quality`.
|
||||
* Parse accept params `str` returning an
|
||||
* object with `.value`, `.quality` and `.params`.
|
||||
* also includes `.originalIndex` for stable sorting
|
||||
*
|
||||
* @param {String} str
|
||||
* @return {Object}
|
||||
* @api private
|
||||
*/
|
||||
|
||||
function quality(str) {
|
||||
var parts = str.split(/ *; */)
|
||||
, val = parts[0];
|
||||
function acceptParams(str, index) {
|
||||
var parts = str.split(/ *; */);
|
||||
var ret = { value: parts[0], quality: 1, params: {}, originalIndex: index };
|
||||
|
||||
var q = parts[1]
|
||||
? parseFloat(parts[1].split(/ *= */)[1])
|
||||
: 1;
|
||||
for (var i = 1; i < parts.length; ++i) {
|
||||
var pms = parts[i].split(/ *= */);
|
||||
if ('q' == pms[0]) {
|
||||
ret.quality = parseFloat(pms[1]);
|
||||
} else {
|
||||
ret.params[pms[0]] = pms[1];
|
||||
}
|
||||
}
|
||||
|
||||
return { value: val, quality: q };
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -247,7 +292,7 @@ exports.escape = function(html) {
|
||||
*/
|
||||
|
||||
exports.pathRegexp = function(path, keys, sensitive, strict) {
|
||||
if (path instanceof RegExp) return path;
|
||||
if (toString.call(path) == '[object RegExp]') return path;
|
||||
if (Array.isArray(path)) path = '(' + path.join('|') + ')';
|
||||
path = path
|
||||
.concat(strict ? '' : '/?')
|
||||
@@ -266,4 +311,23 @@ exports.pathRegexp = function(path, keys, sensitive, strict) {
|
||||
.replace(/([\/.])/g, '\\$1')
|
||||
.replace(/\*/g, '(.*)');
|
||||
return new RegExp('^' + path + '$', sensitive ? '' : 'i');
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Decodes a URI component. Returns
|
||||
* the original string if the component
|
||||
* is malformed.
|
||||
*
|
||||
* @param {String} str
|
||||
* @return {String}
|
||||
* @api private
|
||||
*/
|
||||
|
||||
exports.decode = function(str) {
|
||||
try {
|
||||
return decodeURIComponent(str);
|
||||
} catch (e) {
|
||||
return str;
|
||||
}
|
||||
}
|
||||
|
||||
+7
-6
@@ -8,7 +8,7 @@ var path = require('path')
|
||||
, dirname = path.dirname
|
||||
, basename = path.basename
|
||||
, extname = path.extname
|
||||
, exists = fs.existsSync || path.existsSync
|
||||
, exists = fs.existsSync || path.existsSync
|
||||
, join = path.join;
|
||||
|
||||
/**
|
||||
@@ -22,9 +22,9 @@ module.exports = View;
|
||||
*
|
||||
* Options:
|
||||
*
|
||||
* - `defaultEngine` the default template engine name
|
||||
* - `engines` template engine require() cache
|
||||
* - `root` root path for view lookup
|
||||
* - `defaultEngine` the default template engine name
|
||||
* - `engines` template engine require() cache
|
||||
* - `root` root path for view lookup
|
||||
*
|
||||
* @param {String} name
|
||||
* @param {Object} options
|
||||
@@ -38,7 +38,8 @@ function View(name, options) {
|
||||
var engines = options.engines;
|
||||
this.defaultEngine = options.defaultEngine;
|
||||
var ext = this.ext = extname(name);
|
||||
if (!ext) name += (ext = this.ext = '.' + this.defaultEngine);
|
||||
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);
|
||||
}
|
||||
@@ -72,5 +73,5 @@ View.prototype.lookup = function(path){
|
||||
*/
|
||||
|
||||
View.prototype.render = function(options, fn){
|
||||
this.engine(this.path, options, fn);
|
||||
return this.engine(this.path, options, fn);
|
||||
};
|
||||
|
||||
+44
-29
@@ -1,36 +1,49 @@
|
||||
{
|
||||
"name": "express",
|
||||
"description": "Sinatra inspired web development framework",
|
||||
"version": "3.0.0beta7",
|
||||
"version": "3.4.4",
|
||||
"author": "TJ Holowaychuk <tj@vision-media.ca>",
|
||||
"contributors": [
|
||||
{ "name": "TJ Holowaychuk", "email": "tj@vision-media.ca" },
|
||||
{ "name": "Aaron Heckmann", "email": "aaron.heckmann+github@gmail.com" },
|
||||
{ "name": "Ciaran Jessup", "email": "ciaranj@gmail.com" },
|
||||
{ "name": "Guillermo Rauch", "email": "rauchg@gmail.com" }
|
||||
"contributors": [
|
||||
{
|
||||
"name": "TJ Holowaychuk",
|
||||
"email": "tj@vision-media.ca"
|
||||
},
|
||||
{
|
||||
"name": "Aaron Heckmann",
|
||||
"email": "aaron.heckmann+github@gmail.com"
|
||||
},
|
||||
{
|
||||
"name": "Ciaran Jessup",
|
||||
"email": "ciaranj@gmail.com"
|
||||
},
|
||||
{
|
||||
"name": "Guillermo Rauch",
|
||||
"email": "rauchg@gmail.com"
|
||||
}
|
||||
],
|
||||
"dependencies": {
|
||||
"connect": "2.3.9",
|
||||
"commander": "0.6.1",
|
||||
"connect": "2.11.0",
|
||||
"commander": "1.3.2",
|
||||
"range-parser": "0.0.4",
|
||||
"response-send": "0.0.1",
|
||||
"mkdirp": "0.3.3",
|
||||
"cookie": "0.0.3",
|
||||
"fresh": "0.1.0",
|
||||
"methods": "0.0.1",
|
||||
"send": "0.0.2",
|
||||
"debug": "*"
|
||||
"mkdirp": "0.3.5",
|
||||
"cookie": "0.1.0",
|
||||
"buffer-crc32": "0.2.1",
|
||||
"fresh": "0.2.0",
|
||||
"methods": "0.1.0",
|
||||
"send": "0.1.4",
|
||||
"cookie-signature": "1.0.1",
|
||||
"debug": ">= 0.7.3 < 1"
|
||||
},
|
||||
"devDependencies": {
|
||||
"ejs": "*",
|
||||
"mocha": "*",
|
||||
"jade": "*",
|
||||
"hjs": "*",
|
||||
"stylus": "*",
|
||||
"should": "*",
|
||||
"connect-redis": "*",
|
||||
"github-flavored-markdown": "*",
|
||||
"supertest": "0.0.1"
|
||||
"ejs": ">= 0.8.4 < 1",
|
||||
"mocha": ">= 1.13.0 < 2",
|
||||
"jade": "0.30.0",
|
||||
"hjs": ">= 0.0.6 < 1",
|
||||
"stylus": ">= 0.39.1 < 1",
|
||||
"should": ">= 2.0.2 < 3",
|
||||
"connect-redis": ">= 1.4.5 < 2",
|
||||
"marked": ">= 0.2.9 < 1",
|
||||
"supertest": ">= 0.8.1 < 1"
|
||||
},
|
||||
"keywords": [
|
||||
"express",
|
||||
@@ -43,14 +56,16 @@
|
||||
"app",
|
||||
"api"
|
||||
],
|
||||
"publishConfig": { "tag": "3.0" },
|
||||
"repository": "git://github.com/visionmedia/express",
|
||||
"main": "index",
|
||||
"bin": { "express": "./bin/express" },
|
||||
"bin": {
|
||||
"express": "./bin/express"
|
||||
},
|
||||
"scripts": {
|
||||
"prepublish" : "npm prune",
|
||||
"prepublish": "npm prune",
|
||||
"test": "make test"
|
||||
},
|
||||
"engines": { "node": "*" }
|
||||
"engines": {
|
||||
"node": ">= 0.8.0"
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Alguns arquivos não foram exibidos porque demasiados arquivos foram alterados neste diff Mostrar Mais
Referência em uma Nova Issue
Bloquear um usuário