Comparar commits
147 Commits
| Autor | SHA1 | Data | |
|---|---|---|---|
| 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 |
@@ -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.6
|
||||
- 0.8
|
||||
|
||||
+174
-77
@@ -1,5 +1,102 @@
|
||||
|
||||
3.0.0rc2 / 2012-08-03
|
||||
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
|
||||
@@ -8,7 +105,7 @@
|
||||
* fix: escape `res.redirect()` link
|
||||
* fix vhost example
|
||||
|
||||
3.0.0rc1 / 2012-07-24
|
||||
3.0.0rc1 / 2012-07-24
|
||||
==================
|
||||
|
||||
* add more examples to view-locals
|
||||
@@ -19,12 +116,12 @@
|
||||
* fix `express(1)` -h flag, use -H for hogan. Closes #1245
|
||||
* fix `res.sendfile()` socket error handling regression
|
||||
|
||||
3.0.0beta7 / 2012-07-16
|
||||
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
|
||||
@@ -34,7 +131,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
|
||||
@@ -45,7 +142,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`
|
||||
@@ -57,7 +154,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]
|
||||
@@ -66,7 +163,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
|
||||
@@ -74,13 +171,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`
|
||||
@@ -89,14 +186,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
|
||||
@@ -111,7 +208,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
|
||||
@@ -127,7 +224,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)`
|
||||
@@ -182,54 +279,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
|
||||
@@ -238,7 +335,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
|
||||
@@ -249,17 +346,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
|
||||
@@ -267,25 +364,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
|
||||
@@ -297,14 +394,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!
|
||||
@@ -316,7 +413,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`
|
||||
@@ -324,14 +421,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
|
||||
@@ -350,7 +447,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
|
||||
@@ -358,30 +455,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()`
|
||||
@@ -391,7 +488,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()`
|
||||
@@ -400,18 +497,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
|
||||
@@ -425,7 +522,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
|
||||
@@ -433,14 +530,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
|
||||
@@ -451,20 +548,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
|
||||
@@ -473,14 +570,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
|
||||
@@ -498,13 +595,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
|
||||
@@ -537,46 +634,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()`
|
||||
@@ -584,7 +681,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.
|
||||
@@ -598,7 +695,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.
|
||||
@@ -611,7 +708,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
|
||||
@@ -630,7 +727,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
|
||||
@@ -653,7 +750,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
|
||||
@@ -666,7 +763,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
|
||||
==================
|
||||
@@ -684,7 +781,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
|
||||
==================
|
||||
|
||||
@@ -819,7 +916,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
|
||||
==================
|
||||
|
||||
@@ -886,16 +983,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
|
||||
|
||||
+5
-1
@@ -26,4 +26,8 @@ lib-cov:
|
||||
benchmark:
|
||||
@./support/bench
|
||||
|
||||
.PHONY: test test-unit test-acceptance benchmark
|
||||
clean:
|
||||
rm -f coverage.html
|
||||
rm -fr lib-cov
|
||||
|
||||
.PHONY: test test-unit test-acceptance benchmark clean
|
||||
|
||||
+4
-8
@@ -1,4 +1,3 @@
|
||||
|
||||

|
||||
|
||||
Fast, unopinionated, minimalist web framework for [node](http://nodejs.org). [](http://travis-ci.org/visionmedia/express)
|
||||
@@ -18,10 +17,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:
|
||||
@@ -74,8 +69,9 @@ app.listen(3000);
|
||||
|
||||
## 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
|
||||
|
||||
@@ -107,7 +103,7 @@ authors:
|
||||
54 Aaron Heckmann 1.5%
|
||||
34 csausdev 1.0%
|
||||
26 ciaranj 0.7%
|
||||
21 Robert Sköld 0.6%
|
||||
21 Robert Sköld 0.6%
|
||||
6 Guillermo Rauch 0.2%
|
||||
3 Dav Glass 0.1%
|
||||
3 Nick Poulden 0.1%
|
||||
@@ -153,7 +149,7 @@ authors:
|
||||
1 Jonathan Zacsh 0.0%
|
||||
1 Justin Lilly 0.0%
|
||||
1 Ken Sato 0.0%
|
||||
1 Maciej Małecki 0.0%
|
||||
1 Maciej Małecki 0.0%
|
||||
1 Masahiro Hayashi 0.0%
|
||||
```
|
||||
|
||||
|
||||
@@ -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.
|
||||
*/
|
||||
@@ -195,6 +210,7 @@ var app = [
|
||||
, ''
|
||||
, 'var express = require(\'express\')'
|
||||
, ' , routes = require(\'./routes\')'
|
||||
, ' , user = require(\'./routes/user\')'
|
||||
, ' , http = require(\'http\')'
|
||||
, ' , path = require(\'path\');'
|
||||
, ''
|
||||
@@ -217,6 +233,7 @@ var app = [
|
||||
, '});'
|
||||
, ''
|
||||
, '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\'));'
|
||||
@@ -280,6 +297,7 @@ function createApplicationAt(path) {
|
||||
|
||||
mkdir(path + '/routes', function(){
|
||||
write(path + '/routes/index.js', index);
|
||||
write(path + '/routes/user.js', users);
|
||||
});
|
||||
|
||||
mkdir(path + '/views', function(){
|
||||
|
||||
@@ -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');
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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,3 @@
|
||||
|
||||
/**
|
||||
* Module dependencies.
|
||||
*/
|
||||
@@ -21,11 +20,13 @@ api.use(express.bodyParser());
|
||||
*/
|
||||
|
||||
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();
|
||||
});
|
||||
|
||||
|
||||
@@ -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,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,7 +3,7 @@
|
||||
* Module dependencies.
|
||||
*/
|
||||
|
||||
var express = require('../../')
|
||||
var express = require('../..')
|
||||
, format = require('util').format;
|
||||
|
||||
var app = module.exports = express()
|
||||
@@ -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,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.
|
||||
@@ -11,9 +11,11 @@ var express = require('../..')
|
||||
|
||||
// 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}
|
||||
@@ -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
|
||||
+17
-20
@@ -5,46 +5,43 @@
|
||||
|
||||
var express = require('../..');
|
||||
|
||||
// Edit /etc/vhosts
|
||||
/*
|
||||
edit /etc/vhosts:
|
||||
|
||||
// First app
|
||||
127.0.0.1 foo.example.com
|
||||
127.0.0.1 bar.example.com
|
||||
127.0.0.1 example.com
|
||||
*/
|
||||
|
||||
var one = express();
|
||||
// Main app
|
||||
|
||||
one.use(express.logger());
|
||||
var main = express();
|
||||
|
||||
one.get('/', function(req, res){
|
||||
res.send('Hello from app one!')
|
||||
main.use(express.logger('dev'));
|
||||
|
||||
main.get('/', function(req, res){
|
||||
res.send('Hello from main app!')
|
||||
});
|
||||
|
||||
one.get('/:sub', function(req, res){
|
||||
main.get('/:sub', function(req, res){
|
||||
res.send('requsted ' + req.params.sub);
|
||||
});
|
||||
|
||||
// App two
|
||||
|
||||
var two = express();
|
||||
|
||||
two.get('/', function(req, res){
|
||||
res.send('Hello from app two!')
|
||||
});
|
||||
|
||||
// Redirect app
|
||||
|
||||
var redirect = express();
|
||||
|
||||
redirect.all('*', function(req, res){
|
||||
console.log(req.subdomains);
|
||||
res.redirect('http://localhost:3000/' + req.subdomains[0]);
|
||||
res.redirect('http://example.com:3000/' + req.subdomains[0]);
|
||||
});
|
||||
|
||||
// Main app
|
||||
|
||||
var app = express();
|
||||
|
||||
app.use(express.vhost('*.localhost', redirect))
|
||||
app.use(express.vhost('localhost', one));
|
||||
app.use(express.vhost('dev', two));
|
||||
app.use(express.vhost('*.example.com', redirect))
|
||||
app.use(express.vhost('example.com', main));
|
||||
|
||||
app.listen(3000);
|
||||
console.log('Express app started on port 3000');
|
||||
console.log('Express app started on port 3000');
|
||||
|
||||
@@ -101,11 +101,6 @@ app.get('/middleware-locals', count2, users2, function(req, res, next){
|
||||
res.render('user', { title: 'Users' });
|
||||
});
|
||||
|
||||
|
||||
app.get('/locals', function(req, res){
|
||||
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
|
||||
|
||||
+22
-22
@@ -9,12 +9,10 @@ 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');
|
||||
, join = path.join;
|
||||
|
||||
/**
|
||||
* Application prototype.
|
||||
@@ -33,7 +31,6 @@ var app = exports = module.exports = {};
|
||||
*/
|
||||
|
||||
app.init = function(){
|
||||
var self = this;
|
||||
this.cache = {};
|
||||
this.settings = {};
|
||||
this.engines = {};
|
||||
@@ -48,10 +45,10 @@ app.init = function(){
|
||||
*/
|
||||
|
||||
app.defaultConfiguration = function(){
|
||||
var self = this;
|
||||
|
||||
// default settings
|
||||
this.enable('x-powered-by');
|
||||
this.set('env', process.env.NODE_ENV || 'development');
|
||||
this.set('subdomain offset', 2);
|
||||
debug('booting in %s mode', this.get('env'));
|
||||
|
||||
// implicit middleware
|
||||
@@ -82,7 +79,7 @@ app.defaultConfiguration = function(){
|
||||
this.locals.settings = this.settings;
|
||||
|
||||
// default configuration
|
||||
this.enable('jsonp callback');
|
||||
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 = '/';
|
||||
@@ -164,7 +161,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 seeessly within Express.
|
||||
*
|
||||
* @param {String} ext
|
||||
* @param {Function} fn
|
||||
@@ -401,16 +398,20 @@ 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);
|
||||
|
||||
// if no router attacked 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);
|
||||
@@ -484,9 +484,9 @@ 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
|
||||
defaultEngine: this.get('view engine'),
|
||||
root: this.get('views'),
|
||||
engines: engines
|
||||
});
|
||||
|
||||
if (!view.path) {
|
||||
@@ -522,7 +522,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
|
||||
|
||||
+4
-7
@@ -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;
|
||||
|
||||
/**
|
||||
@@ -23,13 +20,13 @@ exports = module.exports = createApplication;
|
||||
* Framework version.
|
||||
*/
|
||||
|
||||
exports.version = '3.0.0rc2';
|
||||
exports.version = '3.1.0';
|
||||
|
||||
/**
|
||||
* Expose mime.
|
||||
*/
|
||||
|
||||
exports.mime = send.mime;
|
||||
exports.mime = connect.mime;
|
||||
|
||||
/**
|
||||
* Create an express application.
|
||||
@@ -49,7 +46,7 @@ function createApplication() {
|
||||
|
||||
/**
|
||||
* Expose connect.middleware as express.*
|
||||
* for example `express.logger` etc.
|
||||
* for example `express.logger` etc.
|
||||
*/
|
||||
|
||||
for (var key in connect.middleware) {
|
||||
|
||||
+1
-1
@@ -18,7 +18,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;
|
||||
|
||||
+29
-20
@@ -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':
|
||||
@@ -67,7 +67,7 @@ req.header = function(name){
|
||||
* or array is given the _best_ match, if any is returned.
|
||||
*
|
||||
* Examples:
|
||||
*
|
||||
*
|
||||
* // Accept: text/html
|
||||
* req.accepts('html');
|
||||
* // => "html"
|
||||
@@ -261,7 +261,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 +271,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 +303,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
|
||||
@@ -377,39 +377,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(){
|
||||
var offset = this.app.get('subdomain offset');
|
||||
return this.get('Host')
|
||||
.split('.')
|
||||
.slice(0, -2)
|
||||
.reverse();
|
||||
.reverse()
|
||||
.slice(offset);
|
||||
});
|
||||
|
||||
/**
|
||||
|
||||
+144
-68
@@ -2,18 +2,17 @@
|
||||
* 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')
|
||||
, crc = require('crc')
|
||||
, mime = connect.mime
|
||||
, basename = path.basename
|
||||
, extname = path.extname
|
||||
@@ -94,9 +93,6 @@ res.send = function(body){
|
||||
}
|
||||
}
|
||||
|
||||
// convert string objects to primitives
|
||||
if (body instanceof String) body = body.toString();
|
||||
|
||||
switch (typeof body) {
|
||||
// response status
|
||||
case 'number':
|
||||
@@ -133,9 +129,9 @@ res.send = function(body){
|
||||
// ETag support
|
||||
// TODO: W/ support
|
||||
if (len > 1024) {
|
||||
if (!this.get('ETag')) this.set('ETag', Buffer.isBuffer(body)
|
||||
? crc.buffer.crc32(body)
|
||||
: crc.crc32(body));
|
||||
if (!this.get('ETag')) {
|
||||
this.set('ETag', etag(body));
|
||||
}
|
||||
}
|
||||
|
||||
// freshness
|
||||
@@ -145,6 +141,7 @@ res.send = function(body){
|
||||
if (204 == this.statusCode || 304 == this.statusCode) {
|
||||
this.removeHeader('Content-Type');
|
||||
this.removeHeader('Content-Length');
|
||||
this.removeHeader('Transfer-Encoding');
|
||||
body = '';
|
||||
}
|
||||
|
||||
@@ -182,21 +179,64 @@ 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) {
|
||||
this.set('Content-Type', 'text/javascript');
|
||||
body = callback.replace(/[^[]\w$.]/g, '') + '(' + body + ');';
|
||||
var cb = callback.replace(/[^\[\]\w$.]/g, '');
|
||||
body = cb + ' && ' + cb + '(' + body + ');';
|
||||
}
|
||||
|
||||
return this.send(body);
|
||||
@@ -204,7 +244,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`
|
||||
@@ -226,7 +266,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);
|
||||
@@ -371,11 +411,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' });
|
||||
* }
|
||||
@@ -388,11 +428,11 @@ res.type = function(type){
|
||||
* text: function(){
|
||||
* res.send('hey');
|
||||
* },
|
||||
*
|
||||
*
|
||||
* html: function(){
|
||||
* res.send('<p>hey</p>');
|
||||
* },
|
||||
*
|
||||
*
|
||||
* json: function(){
|
||||
* res.send({ message: 'hey' });
|
||||
* }
|
||||
@@ -410,12 +450,12 @@ 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);
|
||||
|
||||
@@ -458,24 +498,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;
|
||||
@@ -533,21 +576,24 @@ 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 ('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
|
||||
@@ -555,41 +601,30 @@ 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];
|
||||
}
|
||||
, req = this.req;
|
||||
|
||||
// setup redirect map
|
||||
var map = { back: req.get('Referrer') || '/' };
|
||||
@@ -608,16 +643,58 @@ res.redirect = function(url){
|
||||
} else if ('/' != url[0]) {
|
||||
url = path + '/' + url;
|
||||
}
|
||||
|
||||
// Absolute
|
||||
var host = req.get('Host');
|
||||
url = '//' + 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 app = this.app
|
||||
, 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(){
|
||||
@@ -632,7 +709,6 @@ res.redirect = function(url){
|
||||
|
||||
// Respond
|
||||
this.statusCode = status;
|
||||
this.set('Location', url);
|
||||
this.set('Content-Length', Buffer.byteLength(body));
|
||||
this.end(head ? null : body);
|
||||
};
|
||||
@@ -665,7 +741,7 @@ res.render = function(view, options, fn){
|
||||
}
|
||||
|
||||
// merge res.locals
|
||||
options.locals = self.locals;
|
||||
options._locals = self.locals;
|
||||
|
||||
// default callback to respond
|
||||
fn = fn || function(err, str){
|
||||
@@ -675,4 +751,4 @@ res.render = function(view, options, fn){
|
||||
|
||||
// render
|
||||
app.render(view, options, fn);
|
||||
};
|
||||
};
|
||||
|
||||
+25
-47
@@ -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) {
|
||||
@@ -104,9 +103,6 @@ Router.prototype._dispatch = function(req, res, next){
|
||||
// match route
|
||||
req.route = route = self.matchRequest(req, i);
|
||||
|
||||
// implied OPTIONS
|
||||
if (!route && 'OPTIONS' == req.method) return self._options(req, res);
|
||||
|
||||
// no route
|
||||
if (!route) return next(err);
|
||||
debug('matched %s %s', route.method, route.path);
|
||||
@@ -144,7 +140,7 @@ Router.prototype._dispatch = function(req, res, next){
|
||||
};
|
||||
|
||||
param(err);
|
||||
|
||||
|
||||
// single param callbacks
|
||||
function paramCallback(err) {
|
||||
var fn = paramCallbacks[paramIndex++];
|
||||
@@ -162,7 +158,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);
|
||||
}
|
||||
@@ -173,41 +170,6 @@ Router.prototype._dispatch = function(req, res, next){
|
||||
})(0);
|
||||
};
|
||||
|
||||
/**
|
||||
* Respond to __OPTIONS__ method.
|
||||
*
|
||||
* @param {IncomingMessage} req
|
||||
* @param {ServerResponse} res
|
||||
* @api private
|
||||
*/
|
||||
|
||||
Router.prototype._options = function(req, res){
|
||||
var path = parse(req).pathname
|
||||
, body = this._optionsFor(path).join(',');
|
||||
res.set('Allow', body).send(body);
|
||||
};
|
||||
|
||||
/**
|
||||
* Return an array of HTTP verbs or "options" for `path`.
|
||||
*
|
||||
* @param {String} path
|
||||
* @return {Array}
|
||||
* @api private
|
||||
*/
|
||||
|
||||
Router.prototype._optionsFor = function(path){
|
||||
var self = this;
|
||||
return methods.filter(function(method){
|
||||
var routes = self.map[method];
|
||||
if (!routes || 'options' == method) return;
|
||||
for (var i = 0, len = routes.length; i < len; ++i) {
|
||||
if (routes[i].match(path)) return true;
|
||||
}
|
||||
}).map(function(method){
|
||||
return method.toUpperCase();
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* Attempt to match a route for `req`
|
||||
* with optional starting index of `i`
|
||||
@@ -282,14 +244,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, i){
|
||||
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;
|
||||
};
|
||||
});
|
||||
|
||||
+14
-1
@@ -3,7 +3,20 @@
|
||||
* Module dependencies.
|
||||
*/
|
||||
|
||||
var mime = require('connect').mime;
|
||||
var mime = require('connect').mime
|
||||
, crc32 = require('buffer-crc32');
|
||||
|
||||
/**
|
||||
* 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`.
|
||||
|
||||
+1
-1
@@ -38,7 +38,7 @@ 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) 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);
|
||||
}
|
||||
|
||||
+8
-8
@@ -1,24 +1,25 @@
|
||||
{
|
||||
"name": "express",
|
||||
"description": "Sinatra inspired web development framework",
|
||||
"version": "3.0.0rc2",
|
||||
"version": "3.1.0",
|
||||
"author": "TJ Holowaychuk <tj@vision-media.ca>",
|
||||
"contributors": [
|
||||
{ "name": "TJ Holowaychuk", "email": "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" }
|
||||
],
|
||||
"dependencies": {
|
||||
"connect": "2.4.2",
|
||||
"connect": "2.7.2",
|
||||
"commander": "0.6.1",
|
||||
"range-parser": "0.0.4",
|
||||
"mkdirp": "0.3.3",
|
||||
"cookie": "0.0.4",
|
||||
"crc": "0.2.0",
|
||||
"cookie": "0.0.5",
|
||||
"buffer-crc32": "0.1.1",
|
||||
"fresh": "0.1.0",
|
||||
"methods": "0.0.1",
|
||||
"send": "0.0.3",
|
||||
"send": "0.1.0",
|
||||
"cookie-signature": "0.0.1",
|
||||
"debug": "*"
|
||||
},
|
||||
"devDependencies": {
|
||||
@@ -43,7 +44,6 @@
|
||||
"app",
|
||||
"api"
|
||||
],
|
||||
"publishConfig": { "tag": "3.0" },
|
||||
"repository": "git://github.com/visionmedia/express",
|
||||
"main": "index",
|
||||
"bin": { "express": "./bin/express" },
|
||||
|
||||
+1
-3
@@ -16,8 +16,6 @@ app.set('views', __dirname + '/views');
|
||||
app.set('view engine', 'jade');
|
||||
app.locals.self = true;
|
||||
|
||||
var repo = require('../package.json');
|
||||
|
||||
app.get('/render', function(req, res){
|
||||
res.render('hello');
|
||||
});
|
||||
@@ -65,4 +63,4 @@ app.get('/match', function(req, res){
|
||||
res.send('Hello World\n');
|
||||
});
|
||||
|
||||
app.listen(8000);
|
||||
app.listen(8000);
|
||||
|
||||
+25
-1
@@ -76,4 +76,28 @@ describe('Router', function(){
|
||||
.expect('foo', done);
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
describe('.multiple callbacks', function(){
|
||||
it('should throw if a callback is null', function(){
|
||||
assert.throws(function () {
|
||||
router.route('get', '/foo', null, function(){});
|
||||
})
|
||||
})
|
||||
|
||||
it('should throw if a callback is undefined', function(){
|
||||
assert.throws(function () {
|
||||
router.route('get', '/foo', undefined, function(){});
|
||||
})
|
||||
})
|
||||
|
||||
it('should throw if a callback is not a function', function(){
|
||||
assert.throws(function () {
|
||||
router.route('get', '/foo', 'not a function', function(){});
|
||||
})
|
||||
})
|
||||
|
||||
it('should not throw if all callbacks are functions', function(){
|
||||
router.route('get', '/foo', function(){}, function(){});
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
@@ -10,9 +10,9 @@ describe('ejs', function(){
|
||||
.end(function(err, res){
|
||||
res.should.have.status(200);
|
||||
res.should.have.header('Content-Type', 'text/html; charset=utf-8');
|
||||
res.text.should.include('<li>tobi tobi@learnboost.com</li>');
|
||||
res.text.should.include('<li>loki loki@learnboost.com</li>');
|
||||
res.text.should.include('<li>jane jane@learnboost.com</li>');
|
||||
res.text.should.include('<li>tobi <tobi@learnboost.com></li>');
|
||||
res.text.should.include('<li>loki <loki@learnboost.com></li>');
|
||||
res.text.should.include('<li>jane <jane@learnboost.com></li>');
|
||||
done();
|
||||
});
|
||||
})
|
||||
|
||||
@@ -85,7 +85,7 @@ describe('error-pages', function(){
|
||||
request(app)
|
||||
.get('/404')
|
||||
.set('Accept', 'text/plain')
|
||||
.expect(200)
|
||||
.expect(404)
|
||||
.expect('Not found', done);
|
||||
})
|
||||
})
|
||||
|
||||
@@ -61,5 +61,20 @@ describe('app', function(){
|
||||
done();
|
||||
})
|
||||
})
|
||||
|
||||
it('should work "view engine" with leading "."', function(done){
|
||||
var app = express();
|
||||
|
||||
app.set('views', __dirname + '/fixtures');
|
||||
app.engine('.html', render);
|
||||
app.set('view engine', '.html');
|
||||
app.locals.user = { name: 'tobi' };
|
||||
|
||||
app.render('user', function(err, str){
|
||||
if (err) return done(err);
|
||||
str.should.equal('<p>tobi</p>');
|
||||
done();
|
||||
})
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
@@ -57,8 +57,10 @@ describe('app.path()', function(){
|
||||
|
||||
describe('in development', function(){
|
||||
it('should disable "view cache"', function(){
|
||||
process.env.NODE_ENV = 'development';
|
||||
var app = express();
|
||||
app.enabled('view cache').should.be.false;
|
||||
process.env.NODE_ENV = 'test';
|
||||
})
|
||||
})
|
||||
|
||||
|
||||
@@ -1,37 +0,0 @@
|
||||
|
||||
var express = require('../')
|
||||
, request = require('./support/http');
|
||||
|
||||
describe('OPTIONS', function(){
|
||||
it('should default to the routes defined', function(done){
|
||||
var app = express();
|
||||
|
||||
app.del('/', function(){});
|
||||
app.get('/users', function(req, res){});
|
||||
app.put('/users', function(req, res){});
|
||||
|
||||
request(app)
|
||||
.options('/users')
|
||||
.expect('GET,PUT')
|
||||
.expect('Allow', 'GET,PUT', done);
|
||||
})
|
||||
})
|
||||
|
||||
describe('app.options()', function(){
|
||||
it('should override the default behavior', function(done){
|
||||
var app = express();
|
||||
|
||||
app.options('/users', function(req, res){
|
||||
res.set('Allow', 'GET');
|
||||
res.send('GET');
|
||||
});
|
||||
|
||||
app.get('/users', function(req, res){});
|
||||
app.put('/users', function(req, res){});
|
||||
|
||||
request(app)
|
||||
.options('/users')
|
||||
.expect('GET')
|
||||
.expect('Allow', 'GET', done);
|
||||
})
|
||||
})
|
||||
@@ -596,4 +596,9 @@ describe('app.router', function(){
|
||||
.get('/account/edit')
|
||||
.expect('editing user 12', done);
|
||||
})
|
||||
|
||||
it('should be chainable', function(){
|
||||
var app = express();
|
||||
app.get('/', function(){}).should.equal(app);
|
||||
})
|
||||
})
|
||||
|
||||
@@ -0,0 +1,43 @@
|
||||
var express = require('../')
|
||||
, request = require('./support/http');
|
||||
|
||||
describe('app', function(){
|
||||
describe('.VERB()', function(){
|
||||
it('should only call an error handling routing callback when an error is propagated', function(done){
|
||||
var app = express();
|
||||
|
||||
var a = false;
|
||||
var b = false;
|
||||
var c = false;
|
||||
var d = false;
|
||||
|
||||
app.get('/', function(req, res, next){
|
||||
next(new Error('fabricated error'));
|
||||
}, function(req, res, next) {
|
||||
a = true;
|
||||
next();
|
||||
}, function(err, req, res, next){
|
||||
b = true;
|
||||
err.message.should.equal('fabricated error');
|
||||
next(err);
|
||||
}, function(err, req, res, next){
|
||||
c = true;
|
||||
err.message.should.equal('fabricated error');
|
||||
next();
|
||||
}, function(err, req, res, next){
|
||||
d = true;
|
||||
next();
|
||||
}, function(req, res){
|
||||
a.should.be.false;
|
||||
b.should.be.true;
|
||||
c.should.be.true;
|
||||
d.should.be.false;
|
||||
res.send(204);
|
||||
});
|
||||
|
||||
request(app)
|
||||
.get('/')
|
||||
.expect(204, done);
|
||||
})
|
||||
})
|
||||
})
|
||||
+3
-2
@@ -1,6 +1,7 @@
|
||||
|
||||
var express = require('../')
|
||||
, request = require('./support/http');
|
||||
, request = require('./support/http')
|
||||
, assert = require('assert');
|
||||
|
||||
describe('exports', function(){
|
||||
it('should have .version', function(){
|
||||
@@ -14,7 +15,7 @@ describe('exports', function(){
|
||||
})
|
||||
|
||||
it('should expose .mime', function(){
|
||||
express.mime.should.equal(require('connect').mime);
|
||||
assert(express.mime == require('connect').mime, 'express.mime should be connect.mime');
|
||||
})
|
||||
|
||||
it('should expose Router', function(){
|
||||
|
||||
@@ -0,0 +1,94 @@
|
||||
|
||||
var express = require('../')
|
||||
, request = require('./support/http');
|
||||
|
||||
describe('req', function(){
|
||||
describe('.auth', function(){
|
||||
describe('when Authorization is missing', function(){
|
||||
it('should return undefined', function(done){
|
||||
var app = express();
|
||||
|
||||
app.get('/', function(req, res){
|
||||
res.send(req.auth || 'none');
|
||||
});
|
||||
|
||||
request(app)
|
||||
.get('/')
|
||||
.expect('none', done)
|
||||
})
|
||||
})
|
||||
|
||||
describe('when Authorization is malformed', function(){
|
||||
it('should return undefined', function(done){
|
||||
var app = express();
|
||||
|
||||
app.get('/', function(req, res){
|
||||
res.send(req.auth || 'none');
|
||||
});
|
||||
|
||||
request(app)
|
||||
.get('/')
|
||||
.set('Authorization', 'meow')
|
||||
.expect('none', done)
|
||||
})
|
||||
})
|
||||
|
||||
describe('when Authorization is not Basic', function(){
|
||||
it('should return undefined', function(done){
|
||||
var app = express();
|
||||
|
||||
app.get('/', function(req, res){
|
||||
res.send(req.auth || 'none');
|
||||
});
|
||||
|
||||
request(app)
|
||||
.get('/')
|
||||
.set('Authorization', 'Meow dG9iaTpmZXJyZXQ')
|
||||
.expect('none', done)
|
||||
})
|
||||
})
|
||||
|
||||
describe('when encoded string is malformed', function(){
|
||||
it('should return undefined', function(done){
|
||||
var app = express();
|
||||
|
||||
app.get('/', function(req, res){
|
||||
res.send(req.auth || 'none');
|
||||
});
|
||||
|
||||
request(app)
|
||||
.get('/')
|
||||
.set('Authorization', 'Basic Z21ldGh2aW4=')
|
||||
.expect('none', done)
|
||||
})
|
||||
})
|
||||
|
||||
describe('when password contains a colon', function(){
|
||||
it('should return .username and .password', function(done){
|
||||
var app = express();
|
||||
|
||||
app.get('/', function(req, res){
|
||||
res.send(req.auth || 'none');
|
||||
});
|
||||
|
||||
request(app)
|
||||
.get('/')
|
||||
.set('Authorization', 'Basic dG9iaTpmZXJyZXQ6ZmVycmV0')
|
||||
.expect('{"username":"tobi","password":"ferret:ferret"}', done)
|
||||
})
|
||||
})
|
||||
|
||||
it('should return .username and .password', function(done){
|
||||
var app = express();
|
||||
|
||||
app.get('/', function(req, res){
|
||||
res.send(req.auth || 'none');
|
||||
});
|
||||
|
||||
request(app)
|
||||
.get('/')
|
||||
.set('Authorization', 'Basic dG9iaTpmZXJyZXQ=')
|
||||
.expect('{"username":"tobi","password":"ferret"}', done)
|
||||
})
|
||||
})
|
||||
})
|
||||
@@ -0,0 +1,52 @@
|
||||
|
||||
var express = require('../')
|
||||
, request = require('./support/http');
|
||||
|
||||
describe('req', function(){
|
||||
describe('.signedCookies', function(){
|
||||
it('should return a signed JSON cookie', function(done){
|
||||
var app = express()
|
||||
, cookieHeader
|
||||
, val;
|
||||
|
||||
app.use(express.cookieParser('secret'));
|
||||
|
||||
app.use(function(req, res){
|
||||
res.send(req.signedCookies);
|
||||
});
|
||||
|
||||
app.response.req = { secret: 'secret' };
|
||||
app.response.cookie('obj', { foo: 'bar' }, { signed: true });
|
||||
cookieHeader = app.response.get('set-cookie');
|
||||
|
||||
val = JSON.stringify({ obj: { foo: 'bar' } });
|
||||
request(app)
|
||||
.get('/')
|
||||
.set('Cookie', cookieHeader)
|
||||
.expect(val, done);
|
||||
})
|
||||
|
||||
it('should return a signed cookie', function(done){
|
||||
var app = express()
|
||||
, cookieHeader
|
||||
, val;
|
||||
|
||||
app.use(express.cookieParser('secret'));
|
||||
|
||||
app.use(function(req, res){
|
||||
res.send(req.signedCookies);
|
||||
});
|
||||
|
||||
app.response.req = { secret: 'secret' };
|
||||
app.response.cookie('foo', 'bar', { signed: true });
|
||||
cookieHeader = app.response.get('set-cookie');
|
||||
|
||||
val = JSON.stringify({ foo: 'bar' });
|
||||
request(app)
|
||||
.get('/')
|
||||
.set('Cookie', cookieHeader)
|
||||
.expect(val, done);
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
@@ -33,5 +33,55 @@ describe('req', function(){
|
||||
.expect('[]', done);
|
||||
})
|
||||
})
|
||||
|
||||
describe('when subdomain offset is set', function(){
|
||||
describe('when subdomain offset is zero', function(){
|
||||
it('should return an array with the whole domain', function(done){
|
||||
var app = express();
|
||||
app.set('subdomain offset', 0);
|
||||
|
||||
app.use(function(req, res){
|
||||
res.send(req.subdomains);
|
||||
});
|
||||
|
||||
request(app)
|
||||
.get('/')
|
||||
.set('Host', 'tobi.ferrets.sub.example.com')
|
||||
.expect('["com","example","sub","ferrets","tobi"]', done);
|
||||
})
|
||||
})
|
||||
|
||||
describe('when present', function(){
|
||||
it('should return an array', function(done){
|
||||
var app = express();
|
||||
app.set('subdomain offset', 3);
|
||||
|
||||
app.use(function(req, res){
|
||||
res.send(req.subdomains);
|
||||
});
|
||||
|
||||
request(app)
|
||||
.get('/')
|
||||
.set('Host', 'tobi.ferrets.sub.example.com')
|
||||
.expect('["ferrets","tobi"]', done);
|
||||
})
|
||||
})
|
||||
|
||||
describe('otherwise', function(){
|
||||
it('should return an empty array', function(done){
|
||||
var app = express();
|
||||
app.set('subdomain offset', 3);
|
||||
|
||||
app.use(function(req, res){
|
||||
res.send(req.subdomains);
|
||||
});
|
||||
|
||||
request(app)
|
||||
.get('/')
|
||||
.set('Host', 'sub.example.com')
|
||||
.expect('[]', done);
|
||||
})
|
||||
})
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
+38
-2
@@ -1,6 +1,7 @@
|
||||
|
||||
var express = require('../')
|
||||
, request = require('./support/http')
|
||||
, utils = require('connect').utils
|
||||
, cookie = require('cookie');
|
||||
|
||||
describe('res', function(){
|
||||
@@ -92,6 +93,41 @@ describe('res', function(){
|
||||
done();
|
||||
})
|
||||
})
|
||||
|
||||
it('should set max-age', function(done){
|
||||
var app = express();
|
||||
|
||||
app.use(function(req, res){
|
||||
res.cookie('name', 'tobi', { maxAge: 1000 });
|
||||
res.end();
|
||||
});
|
||||
|
||||
request(app)
|
||||
.get('/')
|
||||
.end(function(err, res){
|
||||
res.headers['set-cookie'][0].should.include('Max-Age=1');
|
||||
done();
|
||||
})
|
||||
})
|
||||
|
||||
it('should not mutate the options object', function(done){
|
||||
var app = express();
|
||||
|
||||
var options = { maxAge: 1000 };
|
||||
var optionsCopy = utils.merge({}, options);
|
||||
|
||||
app.use(function(req, res){
|
||||
res.cookie('name', 'tobi', options)
|
||||
res.end();
|
||||
});
|
||||
|
||||
request(app)
|
||||
.get('/')
|
||||
.end(function(err, res){
|
||||
options.should.eql(optionsCopy);
|
||||
done();
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
describe('signed', function(){
|
||||
@@ -109,7 +145,7 @@ describe('res', function(){
|
||||
.end(function(err, res){
|
||||
var val = res.headers['set-cookie'][0];
|
||||
val = cookie.parse(val.split('.')[0]);
|
||||
val.user.should.equal('j:{"name":"tobi"}');
|
||||
val.user.should.equal('s:j:{"name":"tobi"}');
|
||||
done();
|
||||
})
|
||||
})
|
||||
@@ -128,7 +164,7 @@ describe('res', function(){
|
||||
request(app)
|
||||
.get('/')
|
||||
.end(function(err, res){
|
||||
var val = ['name=tobi.xJjV2iZ6EI7C8E5kzwbfA9PVLl1ZR07UTnuTgQQ4EnQ; Path=/'];
|
||||
var val = ['name=s%3Atobi.xJjV2iZ6EI7C8E5kzwbfA9PVLl1ZR07UTnuTgQQ4EnQ; Path=/'];
|
||||
res.headers['set-cookie'].should.eql(val);
|
||||
done();
|
||||
})
|
||||
|
||||
+26
-47
@@ -5,55 +5,16 @@ var express = require('../')
|
||||
|
||||
describe('res', function(){
|
||||
describe('.json(object)', function(){
|
||||
describe('when "jsonp callback" is enabled', function(){
|
||||
it('should respond with jsonp', function(done){
|
||||
var app = express();
|
||||
it('should not support jsonp callbacks', function(done){
|
||||
var app = express();
|
||||
|
||||
app.use(function(req, res){
|
||||
res.json({ count: 1 });
|
||||
});
|
||||
app.use(function(req, res){
|
||||
res.json({ foo: 'bar' });
|
||||
});
|
||||
|
||||
request(app)
|
||||
.get('/?callback=something')
|
||||
.end(function(err, res){
|
||||
res.headers.should.have.property('content-type', 'text/javascript; charset=utf-8');
|
||||
res.text.should.equal('something({"count":1});');
|
||||
done();
|
||||
})
|
||||
})
|
||||
|
||||
it('should allow renaming callback', function(done){
|
||||
var app = express();
|
||||
|
||||
app.set('jsonp callback name', 'clb');
|
||||
app.use(function(req, res){
|
||||
res.json({ count: 1 });
|
||||
});
|
||||
|
||||
request(app)
|
||||
.get('/?clb=something')
|
||||
.end(function(err, res){
|
||||
res.headers.should.have.property('content-type', 'text/javascript; charset=utf-8');
|
||||
res.text.should.equal('something({"count":1});');
|
||||
done();
|
||||
})
|
||||
})
|
||||
|
||||
it('should allow []', function(done){
|
||||
var app = express();
|
||||
|
||||
app.use(function(req, res){
|
||||
res.json({ count: 1 });
|
||||
});
|
||||
|
||||
request(app)
|
||||
.get('/?callback=callbacks[123]')
|
||||
.end(function(err, res){
|
||||
res.headers.should.have.property('content-type', 'text/javascript; charset=utf-8');
|
||||
res.text.should.equal('callbacks[123]({"count":1});');
|
||||
done();
|
||||
})
|
||||
})
|
||||
request(app)
|
||||
.get('/?callback=foo')
|
||||
.expect('{"foo":"bar"}', done);
|
||||
})
|
||||
|
||||
describe('when given primitives', function(){
|
||||
@@ -202,4 +163,22 @@ describe('res', function(){
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
it('should not override previous Content-Types', function(done){
|
||||
var app = express();
|
||||
|
||||
app.get('/', function(req, res){
|
||||
res.type('application/vnd.example+json');
|
||||
res.json({ hello: 'world' });
|
||||
});
|
||||
|
||||
request(app)
|
||||
.get('/')
|
||||
.end(function(err, res){
|
||||
res.statusCode.should.equal(200);
|
||||
res.headers.should.have.property('content-type', 'application/vnd.example+json');
|
||||
res.text.should.equal('{"hello":"world"}');
|
||||
done();
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
@@ -0,0 +1,236 @@
|
||||
|
||||
var express = require('../')
|
||||
, request = require('./support/http')
|
||||
, assert = require('assert');
|
||||
|
||||
describe('res', function(){
|
||||
describe('.jsonp(object)', function(){
|
||||
it('should respond with jsonp', function(done){
|
||||
var app = express();
|
||||
|
||||
app.use(function(req, res){
|
||||
res.jsonp({ count: 1 });
|
||||
});
|
||||
|
||||
request(app)
|
||||
.get('/?callback=something')
|
||||
.end(function(err, res){
|
||||
res.headers.should.have.property('content-type', 'text/javascript; charset=utf-8');
|
||||
res.text.should.equal('something && something({"count":1});');
|
||||
done();
|
||||
})
|
||||
})
|
||||
|
||||
it('should allow renaming callback', function(done){
|
||||
var app = express();
|
||||
|
||||
app.set('jsonp callback name', 'clb');
|
||||
|
||||
app.use(function(req, res){
|
||||
res.jsonp({ count: 1 });
|
||||
});
|
||||
|
||||
request(app)
|
||||
.get('/?clb=something')
|
||||
.end(function(err, res){
|
||||
res.headers.should.have.property('content-type', 'text/javascript; charset=utf-8');
|
||||
res.text.should.equal('something && something({"count":1});');
|
||||
done();
|
||||
})
|
||||
})
|
||||
|
||||
it('should allow []', function(done){
|
||||
var app = express();
|
||||
|
||||
app.use(function(req, res){
|
||||
res.jsonp({ count: 1 });
|
||||
});
|
||||
|
||||
request(app)
|
||||
.get('/?callback=callbacks[123]')
|
||||
.end(function(err, res){
|
||||
res.headers.should.have.property('content-type', 'text/javascript; charset=utf-8');
|
||||
res.text.should.equal('callbacks[123] && callbacks[123]({"count":1});');
|
||||
done();
|
||||
})
|
||||
})
|
||||
|
||||
it('should disallow arbitrary js', function(done){
|
||||
var app = express();
|
||||
|
||||
app.use(function(req, res){
|
||||
res.jsonp({});
|
||||
});
|
||||
|
||||
request(app)
|
||||
.get('/?callback=foo;bar()')
|
||||
.end(function(err, res){
|
||||
res.headers.should.have.property('content-type', 'text/javascript; charset=utf-8');
|
||||
res.text.should.equal('foobar && foobar({});');
|
||||
done();
|
||||
})
|
||||
})
|
||||
|
||||
it('should escape utf whitespace', function(done){
|
||||
var app = express();
|
||||
|
||||
app.use(function(req, res){
|
||||
res.jsonp({ str: '\u2028 \u2029 woot' });
|
||||
});
|
||||
|
||||
request(app)
|
||||
.get('/?callback=foo')
|
||||
.end(function(err, res){
|
||||
res.headers.should.have.property('content-type', 'text/javascript; charset=utf-8');
|
||||
res.text.should.equal('foo && foo({"str":"\\u2028 \\u2029 woot"});');
|
||||
done();
|
||||
});
|
||||
});
|
||||
|
||||
describe('when given primitives', function(){
|
||||
it('should respond with json', function(done){
|
||||
var app = express();
|
||||
|
||||
app.use(function(req, res){
|
||||
res.jsonp(null);
|
||||
});
|
||||
|
||||
request(app)
|
||||
.get('/')
|
||||
.end(function(err, res){
|
||||
res.headers.should.have.property('content-type', 'application/json; charset=utf-8');
|
||||
res.text.should.equal('null');
|
||||
done();
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
describe('when given an array', function(){
|
||||
it('should respond with json', function(done){
|
||||
var app = express();
|
||||
|
||||
app.use(function(req, res){
|
||||
res.jsonp(['foo', 'bar', 'baz']);
|
||||
});
|
||||
|
||||
request(app)
|
||||
.get('/')
|
||||
.end(function(err, res){
|
||||
res.headers.should.have.property('content-type', 'application/json; charset=utf-8');
|
||||
res.text.should.equal('["foo","bar","baz"]');
|
||||
done();
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
describe('when given an object', function(){
|
||||
it('should respond with json', function(done){
|
||||
var app = express();
|
||||
|
||||
app.use(function(req, res){
|
||||
res.jsonp({ name: 'tobi' });
|
||||
});
|
||||
|
||||
request(app)
|
||||
.get('/')
|
||||
.end(function(err, res){
|
||||
res.headers.should.have.property('content-type', 'application/json; charset=utf-8');
|
||||
res.text.should.equal('{"name":"tobi"}');
|
||||
done();
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
describe('"json replacer" setting', function(){
|
||||
it('should be passed to JSON.stringify()', function(done){
|
||||
var app = express();
|
||||
|
||||
app.set('json replacer', function(key, val){
|
||||
return '_' == key[0]
|
||||
? undefined
|
||||
: val;
|
||||
});
|
||||
|
||||
app.use(function(req, res){
|
||||
res.jsonp({ name: 'tobi', _id: 12345 });
|
||||
});
|
||||
|
||||
request(app)
|
||||
.get('/')
|
||||
.end(function(err, res){
|
||||
res.text.should.equal('{"name":"tobi"}');
|
||||
done();
|
||||
});
|
||||
})
|
||||
})
|
||||
|
||||
describe('"json spaces" setting', function(){
|
||||
it('should default to 2 in development', function(){
|
||||
process.env.NODE_ENV = 'development';
|
||||
var app = express();
|
||||
app.get('json spaces').should.equal(2);
|
||||
process.env.NODE_ENV = 'test';
|
||||
})
|
||||
|
||||
it('should be undefined otherwise', function(){
|
||||
var app = express();
|
||||
assert(undefined === app.get('json spaces'));
|
||||
})
|
||||
|
||||
it('should be passed to JSON.stringify()', function(done){
|
||||
var app = express();
|
||||
|
||||
app.set('json spaces', 2);
|
||||
|
||||
app.use(function(req, res){
|
||||
res.jsonp({ name: 'tobi', age: 2 });
|
||||
});
|
||||
|
||||
request(app)
|
||||
.get('/')
|
||||
.end(function(err, res){
|
||||
res.text.should.equal('{\n "name": "tobi",\n "age": 2\n}');
|
||||
done();
|
||||
});
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
describe('.json(status, object)', function(){
|
||||
it('should respond with json and set the .statusCode', function(done){
|
||||
var app = express();
|
||||
|
||||
app.use(function(req, res){
|
||||
res.jsonp(201, { id: 1 });
|
||||
});
|
||||
|
||||
request(app)
|
||||
.get('/')
|
||||
.end(function(err, res){
|
||||
res.statusCode.should.equal(201);
|
||||
res.headers.should.have.property('content-type', 'application/json; charset=utf-8');
|
||||
res.text.should.equal('{"id":1}');
|
||||
done();
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
describe('.json(object, status)', function(){
|
||||
it('should respond with json and set the .statusCode for backwards compat', function(done){
|
||||
var app = express();
|
||||
|
||||
app.use(function(req, res){
|
||||
res.jsonp({ id: 1 }, 201);
|
||||
});
|
||||
|
||||
request(app)
|
||||
.get('/')
|
||||
.end(function(err, res){
|
||||
res.statusCode.should.equal(201);
|
||||
res.headers.should.have.property('content-type', 'application/json; charset=utf-8');
|
||||
res.text.should.equal('{"id":1}');
|
||||
done();
|
||||
})
|
||||
})
|
||||
})
|
||||
})
|
||||
@@ -0,0 +1,171 @@
|
||||
|
||||
var express = require('../')
|
||||
, request = require('./support/http');
|
||||
|
||||
describe('res', function(){
|
||||
describe('.location(url)', function(){
|
||||
it('should set the header', function(done){
|
||||
var app = express();
|
||||
|
||||
app.use(function(req, res){
|
||||
res.location('http://google.com').end();
|
||||
});
|
||||
|
||||
request(app)
|
||||
.get('/')
|
||||
.end(function(err, res){
|
||||
res.headers.should.have.property('location', 'http://google.com');
|
||||
done();
|
||||
})
|
||||
})
|
||||
|
||||
describe('with leading //', function(){
|
||||
it('should pass through scheme-relative urls', function(done){
|
||||
var app = express();
|
||||
|
||||
app.use(function(req, res){
|
||||
res.location('//cuteoverload.com').end();
|
||||
});
|
||||
|
||||
request(app)
|
||||
.get('/')
|
||||
.end(function(err, res){
|
||||
res.headers.should.have.property('location', '//cuteoverload.com');
|
||||
done();
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
describe('with leading /', function(){
|
||||
it('should construct scheme-relative urls', function(done){
|
||||
var app = express();
|
||||
|
||||
app.use(function(req, res){
|
||||
res.location('/login').end();
|
||||
});
|
||||
|
||||
request(app)
|
||||
.get('/')
|
||||
.end(function(err, res){
|
||||
res.headers.should.have.property('location', '/login');
|
||||
done();
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
describe('with leading ./', function(){
|
||||
it('should construct path-relative urls', function(done){
|
||||
var app = express();
|
||||
|
||||
app.use(function(req, res){
|
||||
res.location('./edit').end();
|
||||
});
|
||||
|
||||
request(app)
|
||||
.get('/post/1')
|
||||
.end(function(err, res){
|
||||
res.headers.should.have.property('location', '/post/1/./edit');
|
||||
done();
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
describe('with leading ../', function(){
|
||||
it('should construct path-relative urls', function(done){
|
||||
var app = express();
|
||||
|
||||
app.use(function(req, res){
|
||||
res.location('../new').end();
|
||||
});
|
||||
|
||||
request(app)
|
||||
.get('/post/1')
|
||||
.end(function(err, res){
|
||||
res.headers.should.have.property('location', '/post/1/../new');
|
||||
done();
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
describe('without leading /', function(){
|
||||
it('should construct mount-point relative urls', function(done){
|
||||
var app = express();
|
||||
|
||||
app.use(function(req, res){
|
||||
res.location('login').end();
|
||||
});
|
||||
|
||||
request(app)
|
||||
.get('/')
|
||||
.end(function(err, res){
|
||||
res.headers.should.have.property('location', '/login');
|
||||
done();
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
describe('when mounted', function(){
|
||||
describe('deeply', function(){
|
||||
it('should respect the mount-point', function(done){
|
||||
var app = express()
|
||||
, blog = express()
|
||||
, admin = express();
|
||||
|
||||
admin.use(function(req, res){
|
||||
res.location('login').end();
|
||||
});
|
||||
|
||||
app.use('/blog', blog);
|
||||
blog.use('/admin', admin);
|
||||
|
||||
request(app)
|
||||
.get('/blog/admin')
|
||||
.end(function(err, res){
|
||||
res.headers.should.have.property('location', '/blog/admin/login');
|
||||
done();
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
describe('omitting leading /', function(){
|
||||
it('should respect the mount-point', function(done){
|
||||
var app = express()
|
||||
, admin = express();
|
||||
|
||||
admin.use(function(req, res){
|
||||
res.location('admin/login').end();
|
||||
});
|
||||
|
||||
app.use('/blog', admin);
|
||||
|
||||
request(app)
|
||||
.get('/blog')
|
||||
.end(function(err, res){
|
||||
res.headers.should.have.property('location', '/blog/admin/login');
|
||||
done();
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
describe('providing leading /', function(){
|
||||
it('should ignore mount-point', function(done){
|
||||
var app = express()
|
||||
, admin = express();
|
||||
|
||||
admin.use(function(req, res){
|
||||
res.location('/admin/login').end();
|
||||
});
|
||||
|
||||
app.use('/blog', admin);
|
||||
|
||||
request(app)
|
||||
.get('/blog')
|
||||
.end(function(err, res){
|
||||
res.headers.should.have.property('location', '/admin/login');
|
||||
done();
|
||||
})
|
||||
})
|
||||
})
|
||||
})
|
||||
})
|
||||
})
|
||||
+38
-161
@@ -19,164 +19,6 @@ describe('res', function(){
|
||||
done();
|
||||
})
|
||||
})
|
||||
|
||||
describe('with leading //', function(){
|
||||
it('should pass through scheme-relative urls', function(done){
|
||||
var app = express();
|
||||
|
||||
app.use(function(req, res){
|
||||
res.redirect('//cuteoverload.com');
|
||||
});
|
||||
|
||||
request(app)
|
||||
.get('/')
|
||||
.set('Host', 'example.com')
|
||||
.end(function(err, res){
|
||||
res.headers.should.have.property('location', '//cuteoverload.com');
|
||||
done();
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
|
||||
describe('with leading /', function(){
|
||||
it('should construct scheme-relative urls', function(done){
|
||||
var app = express();
|
||||
|
||||
app.use(function(req, res){
|
||||
res.redirect('/login');
|
||||
});
|
||||
|
||||
request(app)
|
||||
.get('/')
|
||||
.set('Host', 'example.com')
|
||||
.end(function(err, res){
|
||||
res.headers.should.have.property('location', '//example.com/login');
|
||||
done();
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
describe('with leading ./', function(){
|
||||
it('should construct path-relative urls', function(done){
|
||||
var app = express();
|
||||
|
||||
app.use(function(req, res){
|
||||
res.redirect('./edit');
|
||||
});
|
||||
|
||||
request(app)
|
||||
.get('/post/1')
|
||||
.set('Host', 'example.com')
|
||||
.end(function(err, res){
|
||||
res.headers.should.have.property('location', '//example.com/post/1/./edit');
|
||||
done();
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
describe('with leading ../', function(){
|
||||
it('should construct path-relative urls', function(done){
|
||||
var app = express();
|
||||
|
||||
app.use(function(req, res){
|
||||
res.redirect('../new');
|
||||
});
|
||||
|
||||
request(app)
|
||||
.get('/post/1')
|
||||
.set('Host', 'example.com')
|
||||
.end(function(err, res){
|
||||
res.headers.should.have.property('location', '//example.com/post/1/../new');
|
||||
done();
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
describe('without leading /', function(){
|
||||
it('should construct mount-point relative urls', function(done){
|
||||
var app = express();
|
||||
|
||||
app.use(function(req, res){
|
||||
res.redirect('login');
|
||||
});
|
||||
|
||||
request(app)
|
||||
.get('/')
|
||||
.set('Host', 'example.com')
|
||||
.end(function(err, res){
|
||||
res.headers.should.have.property('location', '//example.com/login');
|
||||
done();
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
describe('when mounted', function(){
|
||||
describe('deeply', function(){
|
||||
it('should respect the mount-point', function(done){
|
||||
var app = express()
|
||||
, blog = express()
|
||||
, admin = express();
|
||||
|
||||
admin.use(function(req, res){
|
||||
res.redirect('login');
|
||||
});
|
||||
|
||||
app.use('/blog', blog);
|
||||
blog.use('/admin', admin);
|
||||
|
||||
request(app)
|
||||
.get('/blog/admin')
|
||||
.set('Host', 'example.com')
|
||||
.end(function(err, res){
|
||||
res.headers.should.have.property('location', '//example.com/blog/admin/login');
|
||||
done();
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
describe('omitting leading /', function(){
|
||||
it('should respect the mount-point', function(done){
|
||||
var app = express()
|
||||
, admin = express();
|
||||
|
||||
admin.use(function(req, res){
|
||||
res.redirect('admin/login');
|
||||
});
|
||||
|
||||
app.use('/blog', admin);
|
||||
|
||||
request(app)
|
||||
.get('/blog')
|
||||
.set('Host', 'example.com')
|
||||
.end(function(err, res){
|
||||
res.headers.should.have.property('location', '//example.com/blog/admin/login');
|
||||
done();
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
describe('providing leading /', function(){
|
||||
it('should ignore mount-point', function(done){
|
||||
var app = express()
|
||||
, admin = express();
|
||||
|
||||
admin.use(function(req, res){
|
||||
res.redirect('/admin/login');
|
||||
});
|
||||
|
||||
app.use('/blog', admin);
|
||||
|
||||
request(app)
|
||||
.get('/blog')
|
||||
.set('Host', 'example.com')
|
||||
.end(function(err, res){
|
||||
res.headers.should.have.property('location', '//example.com/admin/login');
|
||||
done();
|
||||
})
|
||||
})
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
describe('.redirect(status, url)', function(){
|
||||
@@ -196,7 +38,25 @@ describe('res', function(){
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
|
||||
describe('.redirect(url, status)', function(){
|
||||
it('should set the response status', function(done){
|
||||
var app = express();
|
||||
|
||||
app.use(function(req, res){
|
||||
res.redirect('http://google.com', 303);
|
||||
});
|
||||
|
||||
request(app)
|
||||
.get('/')
|
||||
.end(function(err, res){
|
||||
res.statusCode.should.equal(303);
|
||||
res.headers.should.have.property('location', 'http://google.com');
|
||||
done();
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
describe('when the request method is HEAD', function(){
|
||||
it('should ignore the body', function(done){
|
||||
var app = express();
|
||||
@@ -245,7 +105,7 @@ describe('res', function(){
|
||||
.set('Host', 'http://example.com')
|
||||
.set('Accept', 'text/html')
|
||||
.end(function(err, res){
|
||||
res.text.should.equal('<p>Moved Temporarily. Redirecting to <a href="//http://example.com/<lame>">//http://example.com/<lame></a></p>');
|
||||
res.text.should.equal('<p>Moved Temporarily. Redirecting to <a href="/<lame>">/<lame></a></p>');
|
||||
done();
|
||||
})
|
||||
})
|
||||
@@ -269,6 +129,23 @@ describe('res', function(){
|
||||
done();
|
||||
})
|
||||
})
|
||||
|
||||
it('should encode the url', function(done){
|
||||
var app = express();
|
||||
|
||||
app.use(function(req, res){
|
||||
res.redirect('http://example.com/?param=<script>alert("hax");</script>');
|
||||
});
|
||||
|
||||
request(app)
|
||||
.get('/')
|
||||
.set('Host', 'http://example.com')
|
||||
.set('Accept', 'text/plain, */*')
|
||||
.end(function(err, res){
|
||||
res.text.should.equal('Moved Temporarily. Redirecting to http://example.com/?param=%3Cscript%3Ealert(%22hax%22);%3C/script%3E');
|
||||
done();
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
describe('when accepting neither text or html', function(){
|
||||
@@ -281,7 +158,7 @@ describe('res', function(){
|
||||
|
||||
request(app)
|
||||
.get('/')
|
||||
.set('Accept', 'foo/bar')
|
||||
.set('Accept', 'application/octet-stream')
|
||||
.end(function(err, res){
|
||||
res.should.have.status(302);
|
||||
res.headers.should.have.property('location', 'http://google.com');
|
||||
|
||||
@@ -125,7 +125,7 @@ describe('res', function(){
|
||||
app.locals.user = { name: 'tobi' };
|
||||
|
||||
app.use(function(req, res){
|
||||
res.render('user.jade', {});
|
||||
res.render('user.jade');
|
||||
});
|
||||
|
||||
request(app)
|
||||
@@ -140,7 +140,7 @@ describe('res', function(){
|
||||
|
||||
app.use(function(req, res){
|
||||
res.locals.user = { name: 'tobi' };
|
||||
res.render('user.jade', {});
|
||||
res.render('user.jade');
|
||||
});
|
||||
|
||||
request(app)
|
||||
|
||||
+21
-43
@@ -104,7 +104,7 @@ describe('res', function(){
|
||||
|
||||
request(app)
|
||||
.get('/')
|
||||
.expect('ETag', '-1498647312')
|
||||
.expect('ETag', '"-1498647312"')
|
||||
.end(done);
|
||||
})
|
||||
|
||||
@@ -123,42 +123,6 @@ describe('res', function(){
|
||||
})
|
||||
})
|
||||
|
||||
describe('.send(StringObj)', function(){
|
||||
it('should send as html', function(done){
|
||||
var app = express();
|
||||
|
||||
app.use(function(req, res){
|
||||
res.send(new String('<p>hey</p>'));
|
||||
});
|
||||
|
||||
request(app)
|
||||
.get('/')
|
||||
.end(function(err, res){
|
||||
res.headers.should.have.property('content-type', 'text/html; charset=utf-8');
|
||||
res.text.should.equal('<p>hey</p>');
|
||||
res.statusCode.should.equal(200);
|
||||
done();
|
||||
})
|
||||
})
|
||||
|
||||
it('should not override Content-Type', function(done){
|
||||
var app = express();
|
||||
|
||||
app.use(function(req, res){
|
||||
res.set('Content-Type', 'text/plain').send(new String('hey'));
|
||||
});
|
||||
|
||||
request(app)
|
||||
.get('/')
|
||||
.end(function(err, res){
|
||||
res.headers.should.have.property('content-type', 'text/plain');
|
||||
res.text.should.equal('hey');
|
||||
res.statusCode.should.equal(200);
|
||||
done();
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
describe('.send(Buffer)', function(){
|
||||
it('should send as octet-stream', function(done){
|
||||
var app = express();
|
||||
@@ -187,7 +151,7 @@ describe('res', function(){
|
||||
|
||||
request(app)
|
||||
.get('/')
|
||||
.expect('ETag', '-1498647312')
|
||||
.expect('ETag', '"-1498647312"')
|
||||
.end(done);
|
||||
})
|
||||
|
||||
@@ -242,11 +206,11 @@ describe('res', function(){
|
||||
})
|
||||
|
||||
describe('when .statusCode is 204', function(){
|
||||
it('should strip Content-* fields & body', function(done){
|
||||
it('should strip Content-* fields, Transfer-Encoding field, and body', function(done){
|
||||
var app = express();
|
||||
|
||||
app.use(function(req, res){
|
||||
res.status(204).send('foo');
|
||||
res.status(204).set('Transfer-Encoding', 'chunked').send('foo');
|
||||
});
|
||||
|
||||
request(app)
|
||||
@@ -254,6 +218,7 @@ describe('res', function(){
|
||||
.end(function(err, res){
|
||||
res.headers.should.not.have.property('content-type');
|
||||
res.headers.should.not.have.property('content-length');
|
||||
res.headers.should.not.have.property('transfer-encoding');
|
||||
res.text.should.equal('');
|
||||
done();
|
||||
})
|
||||
@@ -261,11 +226,11 @@ describe('res', function(){
|
||||
})
|
||||
|
||||
describe('when .statusCode is 304', function(){
|
||||
it('should strip Content-* fields & body', function(done){
|
||||
it('should strip Content-* fields, Transfer-Encoding field, and body', function(done){
|
||||
var app = express();
|
||||
|
||||
app.use(function(req, res){
|
||||
res.status(304).send('foo');
|
||||
res.status(304).set('Transfer-Encoding', 'chunked').send('foo');
|
||||
});
|
||||
|
||||
request(app)
|
||||
@@ -273,6 +238,7 @@ describe('res', function(){
|
||||
.end(function(err, res){
|
||||
res.headers.should.not.have.property('content-type');
|
||||
res.headers.should.not.have.property('content-length');
|
||||
res.headers.should.not.have.property('transfer-encoding');
|
||||
res.text.should.equal('');
|
||||
done();
|
||||
})
|
||||
@@ -303,7 +269,7 @@ describe('res', function(){
|
||||
|
||||
request(app)
|
||||
.get('/')
|
||||
.set('If-None-Match', '-1498647312')
|
||||
.set('If-None-Match', '"-1498647312"')
|
||||
.expect(304, done);
|
||||
})
|
||||
|
||||
@@ -322,4 +288,16 @@ describe('res', function(){
|
||||
.expect('hey')
|
||||
.expect(500, done);
|
||||
})
|
||||
|
||||
it('should not support jsonp callbacks', function(done){
|
||||
var app = express();
|
||||
|
||||
app.use(function(req, res){
|
||||
res.send({ foo: 'bar' });
|
||||
});
|
||||
|
||||
request(app)
|
||||
.get('/?callback=foo')
|
||||
.expect('{"foo":"bar"}', done);
|
||||
})
|
||||
})
|
||||
|
||||
@@ -127,7 +127,7 @@ describe('res', function(){
|
||||
});
|
||||
})
|
||||
})
|
||||
|
||||
|
||||
describe('with a relative path', function(){
|
||||
it('should transfer the file', function(done){
|
||||
var app = express();
|
||||
@@ -144,7 +144,7 @@ describe('res', function(){
|
||||
done();
|
||||
});
|
||||
})
|
||||
|
||||
|
||||
it('should serve relative to "root"', function(done){
|
||||
var app = express();
|
||||
|
||||
@@ -160,7 +160,7 @@ describe('res', function(){
|
||||
done();
|
||||
});
|
||||
})
|
||||
|
||||
|
||||
it('should consider ../ malicious when "root" is not set', function(done){
|
||||
var app = express();
|
||||
|
||||
@@ -172,7 +172,7 @@ describe('res', function(){
|
||||
.get('/')
|
||||
.expect(403, done);
|
||||
})
|
||||
|
||||
|
||||
it('should allow ../ when "root" is set', function(done){
|
||||
var app = express();
|
||||
|
||||
@@ -184,7 +184,7 @@ describe('res', function(){
|
||||
.get('/')
|
||||
.expect(200, done);
|
||||
})
|
||||
|
||||
|
||||
it('should disallow requesting out of "root"', function(done){
|
||||
var app = express();
|
||||
|
||||
@@ -196,7 +196,7 @@ describe('res', function(){
|
||||
.get('/')
|
||||
.expect(403, done);
|
||||
})
|
||||
|
||||
|
||||
it('should next(404) when not found', function(done){
|
||||
var app = express()
|
||||
, calls = 0;
|
||||
@@ -208,7 +208,7 @@ describe('res', function(){
|
||||
app.use(function(req, res){
|
||||
assert(0, 'this should not be called');
|
||||
});
|
||||
|
||||
|
||||
app.use(function(err, req, res, next){
|
||||
++calls;
|
||||
next(err);
|
||||
|
||||
@@ -24,6 +24,27 @@ describe('res', function(){
|
||||
res.get('ETag').should.equal('123');
|
||||
})
|
||||
})
|
||||
|
||||
describe('.set(field, values)', function(){
|
||||
it('should set multiple response header fields', function(done){
|
||||
var app = express();
|
||||
|
||||
app.use(function(req, res){
|
||||
res.set('Set-Cookie', ["type=ninja", "language=javascript"]);
|
||||
res.send(res.get('Set-Cookie'));
|
||||
});
|
||||
|
||||
request(app)
|
||||
.get('/')
|
||||
.expect('["type=ninja","language=javascript"]', done);
|
||||
})
|
||||
|
||||
it('should coerce to an array of strings', function(){
|
||||
res.headers = {};
|
||||
res.set('ETag', [123, 456]);
|
||||
JSON.stringify(res.get('ETag')).should.equal('["123","456"]');
|
||||
})
|
||||
})
|
||||
|
||||
describe('.set(object)', function(){
|
||||
it('should set multiple fields', function(done){
|
||||
|
||||
@@ -2,6 +2,26 @@
|
||||
var utils = require('../lib/utils')
|
||||
, assert = require('assert');
|
||||
|
||||
describe('utils.etag(body)', function(){
|
||||
|
||||
var str = 'Hello CRC';
|
||||
var strUTF8 = '<!DOCTYPE html>\n<html>\n<head>\n</head>\n<body><p>自動販売</p></body></html>';
|
||||
|
||||
it('should support strings', function(){
|
||||
utils.etag(str).should.eql('"-2034458343"');
|
||||
})
|
||||
|
||||
it('should support utf8 strings', function(){
|
||||
utils.etag(strUTF8).should.eql('"1395090196"');
|
||||
})
|
||||
|
||||
it('should support buffer', function(){
|
||||
utils.etag(new Buffer(strUTF8)).should.eql('"1395090196"');
|
||||
utils.etag(new Buffer(str)).should.eql('"-2034458343"');
|
||||
})
|
||||
|
||||
})
|
||||
|
||||
describe('utils.isAbsolute()', function(){
|
||||
it('should support windows', function(){
|
||||
assert(utils.isAbsolute('c:\\'));
|
||||
|
||||
Referência em uma Nova Issue
Bloquear um usuário