mirror of
https://github.com/expressjs/express.git
synced 2026-02-26 18:57:43 +00:00
Compare commits
103 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
776ee26bc3 | ||
|
|
ed273448b9 | ||
|
|
4bb91b3f67 | ||
|
|
c5f866098e | ||
|
|
6cfd01be6b | ||
|
|
53b8e25731 | ||
|
|
9e684d45bc | ||
|
|
09d9201787 | ||
|
|
a732d6d471 | ||
|
|
d1bafa0685 | ||
|
|
2604be5491 | ||
|
|
c52d9cdfbe | ||
|
|
aab6b7e721 | ||
|
|
d13cea46d5 | ||
|
|
82731dae6e | ||
|
|
476fba3e8b | ||
|
|
a566624f2d | ||
|
|
c6d7352f5c | ||
|
|
771573be30 | ||
|
|
b7afa4f0f4 | ||
|
|
4a1fa58704 | ||
|
|
6654b7162c | ||
|
|
f26a3cc806 | ||
|
|
66d9a4ad43 | ||
|
|
78d9c98187 | ||
|
|
b686ec1182 | ||
|
|
158f452b50 | ||
|
|
916acd1dd3 | ||
|
|
b4f612474b | ||
|
|
9a884aa9ee | ||
|
|
db5636199e | ||
|
|
8211562cf6 | ||
|
|
9df93d6dec | ||
|
|
1e251af8d3 | ||
|
|
eed0f598a0 | ||
|
|
ec4d4a792a | ||
|
|
84e745f67c | ||
|
|
97edb23dba | ||
|
|
856782c81c | ||
|
|
a7266392f9 | ||
|
|
04b0c44bdf | ||
|
|
99c9eecde5 | ||
|
|
4d65bbf612 | ||
|
|
956aa0cfff | ||
|
|
d874476f0b | ||
|
|
30f9805539 | ||
|
|
46536dee39 | ||
|
|
24087d94df | ||
|
|
d02df2ebd5 | ||
|
|
16ba1f62a3 | ||
|
|
684dd1a3c6 | ||
|
|
8bcdcfeedd | ||
|
|
3bc372aa33 | ||
|
|
fc1c024041 | ||
|
|
89427228d1 | ||
|
|
420225f370 | ||
|
|
44a3fa6359 | ||
|
|
d853c833f0 | ||
|
|
03a796c460 | ||
|
|
75e47f2883 | ||
|
|
a4b2e48dfe | ||
|
|
57cda1578d | ||
|
|
6b1d7a94ff | ||
|
|
49abd7bec1 | ||
|
|
0ebebd80fe | ||
|
|
d157d47c6e | ||
|
|
e3ac2c5b02 | ||
|
|
cd54faa4af | ||
|
|
5beb1c4e30 | ||
|
|
4031aaa591 | ||
|
|
ba00e23630 | ||
|
|
8beb1f21ef | ||
|
|
fa8eec449b | ||
|
|
ab75fa048e | ||
|
|
bb29da5980 | ||
|
|
a4d7b75129 | ||
|
|
0fdceb3de3 | ||
|
|
480d0064e1 | ||
|
|
17bf04d1ef | ||
|
|
3ab30210a2 | ||
|
|
14fcfdee7e | ||
|
|
d4e56c1fa2 | ||
|
|
39ee6f8e79 | ||
|
|
8d21f1e45c | ||
|
|
618484a4fe | ||
|
|
64a234958a | ||
|
|
e4907ce8e8 | ||
|
|
33eaa8329c | ||
|
|
3c4fd57e51 | ||
|
|
a1e42ac33f | ||
|
|
ce7d7bfd8d | ||
|
|
9bd86cdddc | ||
|
|
0117464ac2 | ||
|
|
6f6eec7d8d | ||
|
|
a4e93c0fb8 | ||
|
|
e2ad0d3d6e | ||
|
|
763be5e631 | ||
|
|
c8526932f3 | ||
|
|
5cf29a3d29 | ||
|
|
18a3cc03ee | ||
|
|
ea5e254c7d | ||
|
|
060653bd4c | ||
|
|
c70db96b06 |
@@ -1,3 +1,4 @@
|
||||
language: node_js
|
||||
node_js:
|
||||
- 0.6
|
||||
- "0.8"
|
||||
- "0.10"
|
||||
|
||||
218
History.md
218
History.md
@@ -1,23 +1,73 @@
|
||||
|
||||
3.0.3 / 2012-11-13
|
||||
3.1.2 / 2013-04-12
|
||||
==================
|
||||
|
||||
* add support for custom Accept parameters
|
||||
* update cookie-signature
|
||||
|
||||
3.1.1 / 2013-04-01
|
||||
==================
|
||||
|
||||
* add X-Forwarded-Host support to `req.host`
|
||||
* fix relative redirects
|
||||
* update mkdirp
|
||||
* update buffer-crc32
|
||||
* remove legacy app.configure() method from app template.
|
||||
|
||||
3.1.0 / 2013-01-25
|
||||
==================
|
||||
|
||||
* add support for leading "." in "view engine" setting
|
||||
* add array support to `res.set()`
|
||||
* add node 0.8.x to travis.yml
|
||||
* add "subdomain offset" setting for tweaking `req.subdomains`
|
||||
* add `res.location(url)` implementing `res.redirect()`-like setting of Location
|
||||
* use app.get() for x-powered-by setting for inheritance
|
||||
* fix colons in passwords for `req.auth`
|
||||
|
||||
3.0.6 / 2013-01-04
|
||||
==================
|
||||
|
||||
* add http verb methods to Router
|
||||
* update connect
|
||||
* fix mangling of the `res.cookie()` options object
|
||||
* fix jsonp whitespace escape. Closes #1132
|
||||
|
||||
3.0.5 / 2012-12-19
|
||||
==================
|
||||
|
||||
* add throwing when a non-function is passed to a route
|
||||
* fix: explicitly remove Transfer-Encoding header from 204 and 304 responses
|
||||
* revert "add 'etag' option"
|
||||
|
||||
3.0.4 / 2012-12-05
|
||||
==================
|
||||
|
||||
* add 'etag' option to disable `res.send()` Etags
|
||||
* add escaping of urls in text/plain in `res.redirect()`
|
||||
for old browsers interpreting as html
|
||||
* change crc32 module for a more liberal license
|
||||
* update connect
|
||||
|
||||
3.0.3 / 2012-11-13
|
||||
==================
|
||||
|
||||
* update connect
|
||||
* update cookie module
|
||||
* fix cookie max-age
|
||||
|
||||
3.0.2 / 2012-11-08
|
||||
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
|
||||
3.0.1 / 2012-11-01
|
||||
==================
|
||||
|
||||
* update connect
|
||||
|
||||
3.0.0 / 2012-10-23
|
||||
3.0.0 / 2012-10-23
|
||||
==================
|
||||
|
||||
* add `make clean`
|
||||
@@ -32,7 +82,7 @@
|
||||
* fix view-locals example. Closes #1370
|
||||
* fix route-separation example
|
||||
|
||||
3.0.0rc5 / 2012-09-18
|
||||
3.0.0rc5 / 2012-09-18
|
||||
==================
|
||||
|
||||
* update connect
|
||||
@@ -41,7 +91,7 @@
|
||||
* 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
|
||||
3.0.0rc4 / 2012-08-30
|
||||
==================
|
||||
|
||||
* add `res.jsonp()`. Closes #1307
|
||||
@@ -54,14 +104,14 @@
|
||||
* fix jsonp callback char restrictions
|
||||
* remove old OPTIONS default response
|
||||
|
||||
3.0.0rc3 / 2012-08-13
|
||||
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
|
||||
3.0.0rc2 / 2012-08-03
|
||||
==================
|
||||
|
||||
* add CORS example
|
||||
@@ -70,7 +120,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
|
||||
@@ -81,12 +131,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
|
||||
@@ -96,7 +146,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
|
||||
@@ -107,7 +157,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`
|
||||
@@ -119,7 +169,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]
|
||||
@@ -128,7 +178,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
|
||||
@@ -136,13 +186,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`
|
||||
@@ -151,14 +201,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
|
||||
@@ -173,7 +223,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
|
||||
@@ -189,7 +239,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)`
|
||||
@@ -244,54 +294,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
|
||||
@@ -300,7 +350,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
|
||||
@@ -311,17 +361,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
|
||||
@@ -329,25 +379,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
|
||||
@@ -359,14 +409,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!
|
||||
@@ -378,7 +428,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`
|
||||
@@ -386,14 +436,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
|
||||
@@ -412,7 +462,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
|
||||
@@ -420,30 +470,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()`
|
||||
@@ -453,7 +503,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()`
|
||||
@@ -462,18 +512,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
|
||||
@@ -487,7 +537,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
|
||||
@@ -495,14 +545,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
|
||||
@@ -513,20 +563,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
|
||||
@@ -535,14 +585,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
|
||||
@@ -560,13 +610,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
|
||||
@@ -599,46 +649,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()`
|
||||
@@ -646,7 +696,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.
|
||||
@@ -660,7 +710,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.
|
||||
@@ -673,7 +723,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
|
||||
@@ -692,7 +742,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
|
||||
@@ -715,7 +765,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
|
||||
@@ -728,7 +778,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
|
||||
==================
|
||||
@@ -746,7 +796,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
|
||||
==================
|
||||
|
||||
@@ -881,7 +931,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
|
||||
==================
|
||||
|
||||
@@ -948,16 +998,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
|
||||
|
||||
2
Makefile
2
Makefile
@@ -1,5 +1,5 @@
|
||||
|
||||
MOCHA_OPTS=
|
||||
MOCHA_OPTS= --check-leaks
|
||||
REPORTER = dot
|
||||
|
||||
check: test
|
||||
|
||||
11
Readme.md
11
Readme.md
@@ -1,6 +1,6 @@
|
||||

|
||||
|
||||
Fast, unopinionated, minimalist web framework for [node](http://nodejs.org). [](http://travis-ci.org/visionmedia/express)
|
||||
Fast, unopinionated, minimalist web framework for [node](http://nodejs.org). [](http://travis-ci.org/visionmedia/express) [](https://gemnasium.com/visionmedia/express)
|
||||
|
||||
```js
|
||||
var express = require('express');
|
||||
@@ -51,7 +51,7 @@ app.listen(3000);
|
||||
The Express philosophy is to provide small, robust tooling for HTTP servers. Making
|
||||
it a great solution for single page applications, web sites, hybrids, or public
|
||||
HTTP APIs.
|
||||
|
||||
|
||||
Built on Connect you can use _only_ what you need, and nothing more, applications
|
||||
can be as big or as small as you like, even a single file. Express does
|
||||
not force you to use any specific ORM or template engine. With support for over
|
||||
@@ -65,7 +65,8 @@ app.listen(3000);
|
||||
* Follow [tjholowaychuk](http://twitter.com/tjholowaychuk) on twitter for updates
|
||||
* Visit the [Wiki](http://github.com/visionmedia/express/wiki)
|
||||
* [日本語ドキュメンテーション](http://hideyukisaito.com/doc/expressjs/) by [hideyukisaito](https://github.com/hideyukisaito)
|
||||
* [Русскоязычная документация](http://express-js.ru/)
|
||||
* [Русскоязычная документация](http://jsman.ru/express/)
|
||||
* Run express examples [online](https://runnable.com/express)
|
||||
|
||||
## Viewing Examples
|
||||
|
||||
@@ -96,7 +97,7 @@ project: express
|
||||
commits: 3559
|
||||
active : 468 days
|
||||
files : 237
|
||||
authors:
|
||||
authors:
|
||||
1891 Tj Holowaychuk 53.1%
|
||||
1285 visionmedia 36.1%
|
||||
182 TJ Holowaychuk 5.1%
|
||||
@@ -153,7 +154,7 @@ authors:
|
||||
1 Masahiro Hayashi 0.0%
|
||||
```
|
||||
|
||||
## License
|
||||
## License
|
||||
|
||||
(The MIT License)
|
||||
|
||||
|
||||
32
bin/express
32
bin/express
@@ -30,7 +30,7 @@ var path = program.args.shift() || '.';
|
||||
|
||||
// end-of-line code
|
||||
|
||||
var eol = 'win32' == os.platform() ? '\r\n' : '\n'
|
||||
var eol = os.EOL
|
||||
|
||||
// Template engine
|
||||
|
||||
@@ -216,27 +216,27 @@ var app = [
|
||||
, ''
|
||||
, 'var app = express();'
|
||||
, ''
|
||||
, 'app.configure(function(){'
|
||||
, ' app.set(\'port\', process.env.PORT || 3000);'
|
||||
, ' app.set(\'views\', __dirname + \'/views\');'
|
||||
, ' app.set(\'view engine\', \':TEMPLATE\');'
|
||||
, ' app.use(express.favicon());'
|
||||
, ' app.use(express.logger(\'dev\'));'
|
||||
, ' app.use(express.bodyParser());'
|
||||
, ' app.use(express.methodOverride());{sess}'
|
||||
, ' app.use(app.router);{css}'
|
||||
, ' app.use(express.static(path.join(__dirname, \'public\')));'
|
||||
, '});'
|
||||
, '// all environments'
|
||||
, 'app.set(\'port\', process.env.PORT || 3000);'
|
||||
, 'app.set(\'views\', __dirname + \'/views\');'
|
||||
, 'app.set(\'view engine\', \':TEMPLATE\');'
|
||||
, 'app.use(express.favicon());'
|
||||
, 'app.use(express.logger(\'dev\'));'
|
||||
, 'app.use(express.bodyParser());'
|
||||
, 'app.use(express.methodOverride());{sess}'
|
||||
, 'app.use(app.router);{css}'
|
||||
, 'app.use(express.static(path.join(__dirname, \'public\')));'
|
||||
, ''
|
||||
, 'app.configure(\'development\', function(){'
|
||||
, '// development only'
|
||||
, 'if (\'development\' == app.get(\'env\')) {'
|
||||
, ' app.use(express.errorHandler());'
|
||||
, '});'
|
||||
, '}'
|
||||
, ''
|
||||
, 'app.get(\'/\', routes.index);'
|
||||
, 'app.get(\'/users\', user.list);'
|
||||
, ''
|
||||
, 'http.createServer(app).listen(app.get(\'port\'), function(){'
|
||||
, ' console.log("Express server listening on port " + app.get(\'port\'));'
|
||||
, ' console.log(\'Express server listening on port \' + app.get(\'port\'));'
|
||||
, '});'
|
||||
, ''
|
||||
].join(eol);
|
||||
@@ -345,7 +345,7 @@ function createApplicationAt(path) {
|
||||
name: 'application-name'
|
||||
, version: '0.0.1'
|
||||
, private: true
|
||||
, scripts: { start: 'node app' }
|
||||
, scripts: { start: 'node app.js' }
|
||||
, dependencies: {
|
||||
express: version
|
||||
}
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
|
||||
/**
|
||||
* Module dependencies.
|
||||
*/
|
||||
@@ -21,6 +20,7 @@ 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');
|
||||
|
||||
@@ -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');
|
||||
|
||||
@@ -34,7 +34,6 @@ app.init = function(){
|
||||
this.cache = {};
|
||||
this.settings = {};
|
||||
this.engines = {};
|
||||
this.viewCallbacks = [];
|
||||
this.defaultConfiguration();
|
||||
};
|
||||
|
||||
@@ -48,6 +47,7 @@ app.defaultConfiguration = function(){
|
||||
// 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
|
||||
@@ -59,6 +59,7 @@ app.defaultConfiguration = function(){
|
||||
this.request.__proto__ = parent.request;
|
||||
this.response.__proto__ = parent.response;
|
||||
this.engines.__proto__ = parent.engines;
|
||||
this.settings.__proto__ = parent.settings;
|
||||
});
|
||||
|
||||
// router
|
||||
@@ -160,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 seamlessly within Express.
|
||||
*
|
||||
* @param {String} ext
|
||||
* @param {Function} fn
|
||||
@@ -249,11 +250,7 @@ app.param = function(name, fn){
|
||||
|
||||
app.set = function(setting, val){
|
||||
if (1 == arguments.length) {
|
||||
if (this.settings.hasOwnProperty(setting)) {
|
||||
return this.settings[setting];
|
||||
} else if (this.parent) {
|
||||
return this.parent.set(setting);
|
||||
}
|
||||
return this.settings[setting];
|
||||
} else {
|
||||
this.settings[setting] = val;
|
||||
return this;
|
||||
@@ -397,15 +394,18 @@ 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 no router attached yet, attach the router
|
||||
if (!this._usedRouter) this.use(this.router);
|
||||
this._router.route.apply(this._router, args);
|
||||
|
||||
// setup route
|
||||
this._router[method].apply(this._router, arguments);
|
||||
return this;
|
||||
};
|
||||
});
|
||||
|
||||
@@ -20,7 +20,7 @@ exports = module.exports = createApplication;
|
||||
* Framework version.
|
||||
*/
|
||||
|
||||
exports.version = '3.0.3';
|
||||
exports.version = '3.1.2';
|
||||
|
||||
/**
|
||||
* Expose mime.
|
||||
@@ -46,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) {
|
||||
|
||||
@@ -18,7 +18,7 @@ var utils = require('./utils');
|
||||
exports.init = function(app){
|
||||
return function expressInit(req, res, next){
|
||||
req.app = res.app = app;
|
||||
if (app.settings['x-powered-by']) 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,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"
|
||||
@@ -202,7 +202,7 @@ req.__defineGetter__('acceptedLanguages', function(){
|
||||
var accept = this.get('Accept-Language');
|
||||
return accept
|
||||
? utils
|
||||
.parseQuality(accept)
|
||||
.parseParams(accept)
|
||||
.map(function(obj){
|
||||
return obj.value;
|
||||
})
|
||||
@@ -226,7 +226,7 @@ req.__defineGetter__('acceptedCharsets', function(){
|
||||
var accept = this.get('Accept-Charset');
|
||||
return accept
|
||||
? utils
|
||||
.parseQuality(accept)
|
||||
.parseParams(accept)
|
||||
.map(function(obj){
|
||||
return obj.value;
|
||||
})
|
||||
@@ -245,7 +245,7 @@ req.__defineGetter__('acceptedCharsets', function(){
|
||||
* the `connect.bodyParser()` middleware.
|
||||
*
|
||||
* @param {String} name
|
||||
* @param {Mixed} defaultValue
|
||||
* @param {Mixed} [defaultValue]
|
||||
* @return {String}
|
||||
* @api public
|
||||
*/
|
||||
@@ -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
|
||||
@@ -393,25 +393,32 @@ req.__defineGetter__('auth', function(){
|
||||
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);
|
||||
});
|
||||
|
||||
/**
|
||||
@@ -433,7 +440,10 @@ req.__defineGetter__('path', function(){
|
||||
*/
|
||||
|
||||
req.__defineGetter__('host', function(){
|
||||
return this.get('Host').split(':')[0];
|
||||
var trustProxy = this.app.get('trust proxy');
|
||||
var host = trustProxy && this.get('X-Forwarded-Host');
|
||||
host = host || this.get('Host');
|
||||
return host.split(':')[0];
|
||||
});
|
||||
|
||||
/**
|
||||
|
||||
153
lib/response.js
153
lib/response.js
@@ -141,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 = '';
|
||||
}
|
||||
|
||||
@@ -186,7 +187,7 @@ res.json = function(obj){
|
||||
// content-type
|
||||
this.charset = this.charset || 'utf-8';
|
||||
this.get('Content-Type') || this.set('Content-Type', 'application/json');
|
||||
|
||||
|
||||
return this.send(body);
|
||||
};
|
||||
|
||||
@@ -222,13 +223,15 @@ res.jsonp = function(obj){
|
||||
var app = this.app;
|
||||
var replacer = app.get('json replacer');
|
||||
var spaces = app.get('json spaces');
|
||||
var body = JSON.stringify(obj, replacer, spaces);
|
||||
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) {
|
||||
this.set('Content-Type', 'text/javascript');
|
||||
@@ -241,7 +244,7 @@ res.jsonp = 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`
|
||||
@@ -263,7 +266,7 @@ res.jsonp = 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);
|
||||
@@ -408,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' });
|
||||
* }
|
||||
@@ -425,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' });
|
||||
* }
|
||||
@@ -459,14 +462,14 @@ res.format = function(obj){
|
||||
this.set('Vary', 'Accept');
|
||||
|
||||
if (key) {
|
||||
this.set('Content-Type', normalizeType(key));
|
||||
this.set('Content-Type', normalizeType(key).value);
|
||||
obj[key](req, this, next);
|
||||
} else if (fn) {
|
||||
fn();
|
||||
} else {
|
||||
var err = new Error('Not Acceptable');
|
||||
err.status = 406;
|
||||
err.types = normalizeTypes(keys);
|
||||
err.types = normalizeTypes(keys).map(function(o){ return o.value });
|
||||
next(err);
|
||||
}
|
||||
|
||||
@@ -495,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;
|
||||
@@ -570,26 +576,89 @@ 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 = 's:' + sign(val, secret);
|
||||
if ('maxAge' in options) options.expires = new Date(Date.now() + options.maxAge);
|
||||
if ('maxAge' in options) {
|
||||
options.expires = new Date(Date.now() + options.maxAge);
|
||||
options.maxAge /= 1000;
|
||||
}
|
||||
if (null == options.path) options.path = '/';
|
||||
options.maxAge /= 1000;
|
||||
this.set('Set-Cookie', cookie.serialize(name, String(val), options));
|
||||
return this;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* 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
|
||||
* to the _Referrer_ or _Referer_ headers or "/".
|
||||
*
|
||||
* Examples:
|
||||
*
|
||||
* res.location('/foo/bar').;
|
||||
* res.location('http://example.com');
|
||||
* res.location('../login'); // /blog/post/1 -> /blog/login
|
||||
*
|
||||
* Mounting:
|
||||
*
|
||||
* When an application is mounted and `res.location()`
|
||||
* is given a path that does _not_ lead with "/" it becomes
|
||||
* relative to the mount-point. For example if the application
|
||||
* is mounted at "/blog", the following would become "/blog/login".
|
||||
*
|
||||
* res.location('login');
|
||||
*
|
||||
* While the leading slash would result in a location of "/login":
|
||||
*
|
||||
* res.location('/login');
|
||||
*
|
||||
* @param {String} url
|
||||
* @api public
|
||||
*/
|
||||
|
||||
res.location = function(url){
|
||||
var app = this.app
|
||||
, req = this.req;
|
||||
|
||||
// setup redirect map
|
||||
var map = { back: req.get('Referrer') || '/' };
|
||||
|
||||
// perform redirect
|
||||
url = map[url] || url;
|
||||
|
||||
// relative
|
||||
if (!~url.indexOf('://') && 0 != url.indexOf('//')) {
|
||||
var path
|
||||
|
||||
// relative to path
|
||||
if ('.' == url[0]) {
|
||||
path = req.originalUrl.split('?')[0]
|
||||
url = path + ('/' == path[path.length - 1] ? '' : '/') + url;
|
||||
// relative to mount-point
|
||||
} else if ('/' != url[0]) {
|
||||
path = app.path();
|
||||
url = path + '/' + url;
|
||||
}
|
||||
}
|
||||
|
||||
// Respond
|
||||
this.set('Location', url);
|
||||
return this;
|
||||
};
|
||||
|
||||
/**
|
||||
* Redirect to the given `url` with optional response `status`
|
||||
* defaulting to 302.
|
||||
*
|
||||
* The given `url` can also be the name of a mapped url, for
|
||||
* example by default express supports "back" which redirects
|
||||
* to the _Referrer_ or _Referer_ headers or "/".
|
||||
* The resulting `url` is determined by `res.location()`, so
|
||||
* it will play nicely with mounted apps, relative paths,
|
||||
* `"back"` etc.
|
||||
*
|
||||
* Examples:
|
||||
*
|
||||
@@ -599,19 +668,6 @@ res.cookie = function(name, val, options){
|
||||
* res.redirect('http://example.com', 301);
|
||||
* res.redirect('../login'); // /blog/post/1 -> /blog/login
|
||||
*
|
||||
* Mounting:
|
||||
*
|
||||
* When an application is mounted, and `res.redirect()`
|
||||
* is given a path that does _not_ lead with "/". For
|
||||
* example suppose a "blog" app is mounted at "/blog",
|
||||
* the following redirect would result in "/blog/login":
|
||||
*
|
||||
* res.redirect('login');
|
||||
*
|
||||
* While the leading slash would result in a redirect to "/login":
|
||||
*
|
||||
* res.redirect('/login');
|
||||
*
|
||||
* @param {String} url
|
||||
* @param {Number} code
|
||||
* @api public
|
||||
@@ -619,8 +675,7 @@ res.cookie = function(name, val, options){
|
||||
|
||||
res.redirect = function(url){
|
||||
var app = this.app
|
||||
, req = this.req
|
||||
, head = 'HEAD' == req.method
|
||||
, head = 'HEAD' == this.req.method
|
||||
, status = 302
|
||||
, body;
|
||||
|
||||
@@ -634,29 +689,14 @@ res.redirect = function(url){
|
||||
}
|
||||
}
|
||||
|
||||
// setup redirect map
|
||||
var map = { back: req.get('Referrer') || '/' };
|
||||
|
||||
// perform redirect
|
||||
url = map[url] || url;
|
||||
|
||||
// relative
|
||||
if (!~url.indexOf('://') && 0 != url.indexOf('//')) {
|
||||
var path = app.path();
|
||||
|
||||
// relative to path
|
||||
if ('.' == url[0]) {
|
||||
url = req.path + '/' + url;
|
||||
// relative to mount-point
|
||||
} else if ('/' != url[0]) {
|
||||
url = path + '/' + url;
|
||||
}
|
||||
}
|
||||
// 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(){
|
||||
@@ -671,7 +711,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);
|
||||
};
|
||||
|
||||
@@ -4,6 +4,7 @@
|
||||
|
||||
var Route = require('./route')
|
||||
, utils = require('../utils')
|
||||
, methods = require('methods')
|
||||
, debug = require('debug')('express:router')
|
||||
, parse = require('connect').utils.parseUrl;
|
||||
|
||||
@@ -15,7 +16,7 @@ exports = module.exports = Router;
|
||||
|
||||
/**
|
||||
* Initialize a new `Router` with the given `options`.
|
||||
*
|
||||
*
|
||||
* @param {Object} options
|
||||
* @api private
|
||||
*/
|
||||
@@ -139,7 +140,7 @@ Router.prototype._dispatch = function(req, res, next){
|
||||
};
|
||||
|
||||
param(err);
|
||||
|
||||
|
||||
// single param callbacks
|
||||
function paramCallback(err) {
|
||||
var fn = paramCallbacks[paramIndex++];
|
||||
@@ -243,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;
|
||||
};
|
||||
});
|
||||
|
||||
86
lib/utils.js
86
lib/utils.js
@@ -4,7 +4,7 @@
|
||||
*/
|
||||
|
||||
var mime = require('connect').mime
|
||||
, crc = require('crc');
|
||||
, crc32 = require('buffer-crc32');
|
||||
|
||||
/**
|
||||
* Return ETag for `body`.
|
||||
@@ -15,15 +15,13 @@ var mime = require('connect').mime
|
||||
*/
|
||||
|
||||
exports.etag = function(body){
|
||||
return '"' + (Buffer.isBuffer(body)
|
||||
? crc.buffer.crc32(body)
|
||||
: crc.crc32(body)) + '"';
|
||||
return '"' + crc32.signed(body) + '"';
|
||||
};
|
||||
|
||||
/**
|
||||
* Make `locals()` bound to the given `obj`.
|
||||
*
|
||||
* This is used for `app.locals` and `res.locals`.
|
||||
*
|
||||
* This is used for `app.locals` and `res.locals`.
|
||||
*
|
||||
* @param {Object} obj
|
||||
* @return {Function}
|
||||
@@ -31,8 +29,6 @@ exports.etag = function(body){
|
||||
*/
|
||||
|
||||
exports.locals = function(obj){
|
||||
obj.viewCallbacks = obj.viewCallbacks || [];
|
||||
|
||||
function locals(obj){
|
||||
for (var key in obj) locals[key] = obj[key];
|
||||
return obj;
|
||||
@@ -79,12 +75,14 @@ exports.flatten = function(arr, ret){
|
||||
* Normalize the given `type`, for example "html" becomes "text/html".
|
||||
*
|
||||
* @param {String} type
|
||||
* @return {String}
|
||||
* @return {Object}
|
||||
* @api private
|
||||
*/
|
||||
|
||||
exports.normalizeType = function(type){
|
||||
return ~type.indexOf('/') ? type : mime.lookup(type);
|
||||
return ~type.indexOf('/')
|
||||
? acceptParams(type)
|
||||
: { value: mime.lookup(type), params: {} };
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -99,9 +97,7 @@ exports.normalizeTypes = function(types){
|
||||
var ret = [];
|
||||
|
||||
for (var i = 0; i < types.length; ++i) {
|
||||
ret.push(~types[i].indexOf('/')
|
||||
? types[i]
|
||||
: mime.lookup(types[i]));
|
||||
ret.push(exports.normalizeType(types[i]));
|
||||
}
|
||||
|
||||
return ret;
|
||||
@@ -127,7 +123,7 @@ exports.acceptsArray = function(types, str){
|
||||
|
||||
for (var i = 0; i < len; ++i) {
|
||||
for (var j = 0, jlen = types.length; j < jlen; ++j) {
|
||||
if (exports.accept(normalized[j].split('/'), accepted[i])) {
|
||||
if (exports.accept(normalized[j], accepted[i])) {
|
||||
return types[j];
|
||||
}
|
||||
}
|
||||
@@ -152,17 +148,34 @@ exports.accepts = function(type, str){
|
||||
/**
|
||||
* Check if `type` array is acceptable for `other`.
|
||||
*
|
||||
* @param {Array} type
|
||||
* @param {Object} type
|
||||
* @param {Object} other
|
||||
* @return {Boolean}
|
||||
* @api private
|
||||
*/
|
||||
|
||||
exports.accept = function(type, other){
|
||||
return (type[0] == other.type || '*' == other.type)
|
||||
&& (type[1] == other.subtype || '*' == other.subtype);
|
||||
var t = type.value.split('/');
|
||||
return (t[0] == other.type || '*' == other.type)
|
||||
&& (t[1] == other.subtype || '*' == other.subtype)
|
||||
&& paramsEqual(type.params, other.params);
|
||||
};
|
||||
|
||||
/**
|
||||
* Check if accept params are equal.
|
||||
*
|
||||
* @param {Object} a
|
||||
* @param {Object} b
|
||||
* @return {Boolean}
|
||||
* @api private
|
||||
*/
|
||||
|
||||
function paramsEqual(a, b){
|
||||
return !Object.keys(a).some(function(k) {
|
||||
return a[k] != b[k];
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Parse accept `str`, returning
|
||||
* an array objects containing
|
||||
@@ -177,7 +190,7 @@ exports.accept = function(type, other){
|
||||
|
||||
exports.parseAccept = function(str){
|
||||
return exports
|
||||
.parseQuality(str)
|
||||
.parseParams(str)
|
||||
.map(function(obj){
|
||||
var parts = obj.value.split('/');
|
||||
obj.type = parts[0];
|
||||
@@ -188,18 +201,18 @@ exports.parseAccept = function(str){
|
||||
|
||||
/**
|
||||
* Parse quality `str`, returning an
|
||||
* array of objects with `.value` and
|
||||
* `.quality`.
|
||||
* array of objects with `.value`,
|
||||
* `.quality` and optional `.params`
|
||||
*
|
||||
* @param {Type} name
|
||||
* @return {Type}
|
||||
* @param {String} str
|
||||
* @return {Array}
|
||||
* @api private
|
||||
*/
|
||||
|
||||
exports.parseQuality = function(str){
|
||||
exports.parseParams = function(str){
|
||||
return str
|
||||
.split(/ *, */)
|
||||
.map(quality)
|
||||
.map(acceptParams)
|
||||
.filter(function(obj){
|
||||
return obj.quality;
|
||||
})
|
||||
@@ -209,23 +222,28 @@ exports.parseQuality = function(str){
|
||||
};
|
||||
|
||||
/**
|
||||
* Parse quality `str` returning an
|
||||
* object with `.value` and `.quality`.
|
||||
* Parse accept params `str` returning an
|
||||
* object with `.value`, `.quality` and `.params`.
|
||||
*
|
||||
* @param {String} str
|
||||
* @return {Object}
|
||||
* @api private
|
||||
*/
|
||||
|
||||
function quality(str) {
|
||||
var parts = str.split(/ *; */)
|
||||
, val = parts[0];
|
||||
function acceptParams(str) {
|
||||
var parts = str.split(/ *; */);
|
||||
var ret = { value: parts[0], quality: 1, params: {} };
|
||||
|
||||
var q = parts[1]
|
||||
? parseFloat(parts[1].split(/ *= */)[1])
|
||||
: 1;
|
||||
for (var i = 1; i < parts.length; ++i) {
|
||||
var pms = parts[i].split(/ *= */);
|
||||
if ('q' == pms[0]) {
|
||||
ret.quality = parseFloat(pms[1]);
|
||||
} else {
|
||||
ret.params[pms[0]] = pms[1];
|
||||
}
|
||||
}
|
||||
|
||||
return { value: val, quality: q };
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -281,4 +299,4 @@ exports.pathRegexp = function(path, keys, sensitive, strict) {
|
||||
.replace(/([\/.])/g, '\\$1')
|
||||
.replace(/\*/g, '(.*)');
|
||||
return new RegExp('^' + path + '$', sensitive ? '' : 'i');
|
||||
}
|
||||
}
|
||||
|
||||
10
lib/view.js
10
lib/view.js
@@ -8,7 +8,7 @@ var path = require('path')
|
||||
, dirname = path.dirname
|
||||
, basename = path.basename
|
||||
, extname = path.extname
|
||||
, exists = fs.existsSync || path.existsSync
|
||||
, exists = fs.existsSync || path.existsSync
|
||||
, join = path.join;
|
||||
|
||||
/**
|
||||
@@ -22,9 +22,9 @@ module.exports = View;
|
||||
*
|
||||
* Options:
|
||||
*
|
||||
* - `defaultEngine` the default template engine name
|
||||
* - `engines` template engine require() cache
|
||||
* - `root` root path for view lookup
|
||||
* - `defaultEngine` the default template engine name
|
||||
* - `engines` template engine require() cache
|
||||
* - `root` root path for view lookup
|
||||
*
|
||||
* @param {String} name
|
||||
* @param {Object} options
|
||||
@@ -38,7 +38,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);
|
||||
}
|
||||
|
||||
43
package.json
43
package.json
@@ -1,25 +1,37 @@
|
||||
{
|
||||
"name": "express",
|
||||
"description": "Sinatra inspired web development framework",
|
||||
"version": "3.0.3",
|
||||
"version": "3.1.2",
|
||||
"author": "TJ Holowaychuk <tj@vision-media.ca>",
|
||||
"contributors": [
|
||||
{ "name": "TJ Holowaychuk", "email": "tj@vision-media.ca" },
|
||||
{ "name": "Aaron Heckmann", "email": "aaron.heckmann+github@gmail.com" },
|
||||
{ "name": "Ciaran Jessup", "email": "ciaranj@gmail.com" },
|
||||
{ "name": "Guillermo Rauch", "email": "rauchg@gmail.com" }
|
||||
"contributors": [
|
||||
{
|
||||
"name": "TJ Holowaychuk",
|
||||
"email": "tj@vision-media.ca"
|
||||
},
|
||||
{
|
||||
"name": "Aaron Heckmann",
|
||||
"email": "aaron.heckmann+github@gmail.com"
|
||||
},
|
||||
{
|
||||
"name": "Ciaran Jessup",
|
||||
"email": "ciaranj@gmail.com"
|
||||
},
|
||||
{
|
||||
"name": "Guillermo Rauch",
|
||||
"email": "rauchg@gmail.com"
|
||||
}
|
||||
],
|
||||
"dependencies": {
|
||||
"connect": "2.7.0",
|
||||
"connect": "2.7.5",
|
||||
"commander": "0.6.1",
|
||||
"range-parser": "0.0.4",
|
||||
"mkdirp": "0.3.3",
|
||||
"mkdirp": "~0.3.4",
|
||||
"cookie": "0.0.5",
|
||||
"crc": "0.2.0",
|
||||
"buffer-crc32": "~0.2.1",
|
||||
"fresh": "0.1.0",
|
||||
"methods": "0.0.1",
|
||||
"send": "0.1.0",
|
||||
"cookie-signature": "0.0.1",
|
||||
"cookie-signature": "1.0.0",
|
||||
"debug": "*"
|
||||
},
|
||||
"devDependencies": {
|
||||
@@ -46,11 +58,14 @@
|
||||
],
|
||||
"repository": "git://github.com/visionmedia/express",
|
||||
"main": "index",
|
||||
"bin": { "express": "./bin/express" },
|
||||
"bin": {
|
||||
"express": "./bin/express"
|
||||
},
|
||||
"scripts": {
|
||||
"prepublish" : "npm prune",
|
||||
"prepublish": "npm prune",
|
||||
"test": "make test"
|
||||
},
|
||||
"engines": { "node": "*" }
|
||||
"engines": {
|
||||
"node": "*"
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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(){});
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
@@ -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();
|
||||
})
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
@@ -15,7 +15,7 @@ describe('req', function(){
|
||||
.get('/')
|
||||
.expect('yes', done);
|
||||
})
|
||||
|
||||
|
||||
it('should return true when present', function(done){
|
||||
var app = express();
|
||||
|
||||
@@ -28,7 +28,7 @@ describe('req', function(){
|
||||
.set('Accept', 'application/json')
|
||||
.expect('yes', done);
|
||||
})
|
||||
|
||||
|
||||
it('should return false otherwise', function(done){
|
||||
var app = express();
|
||||
|
||||
|
||||
@@ -17,7 +17,7 @@ describe('req', function(){
|
||||
.expect('yes', done);
|
||||
})
|
||||
})
|
||||
|
||||
|
||||
describe('when Accept-Charset is not present', function(){
|
||||
it('should return true when present', function(done){
|
||||
var app = express();
|
||||
@@ -31,7 +31,7 @@ describe('req', function(){
|
||||
.set('Accept-Charset', 'foo, bar, utf-8')
|
||||
.expect('yes', done);
|
||||
})
|
||||
|
||||
|
||||
it('should return false otherwise', function(done){
|
||||
var app = express();
|
||||
|
||||
|
||||
@@ -48,6 +48,36 @@ describe('req', function(){
|
||||
})
|
||||
})
|
||||
|
||||
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();
|
||||
|
||||
|
||||
@@ -1,18 +0,0 @@
|
||||
|
||||
var express = require('../');
|
||||
|
||||
function req(ret) {
|
||||
return {
|
||||
get: function(){ return ret }
|
||||
, __proto__: express.request
|
||||
};
|
||||
}
|
||||
|
||||
describe('req', function(){
|
||||
describe('.host', function(){
|
||||
it('should return hostname', function(){
|
||||
req('example.com:3000').host.should.equal('example.com');
|
||||
req('example.com').host.should.equal('example.com');
|
||||
})
|
||||
})
|
||||
})
|
||||
@@ -9,6 +9,10 @@ describe('req', function(){
|
||||
, cookieHeader
|
||||
, val;
|
||||
|
||||
/* So we use the same serialization for expected results. */
|
||||
var replacer = app.get('json replacer')
|
||||
, spaces = app.get('json spaces');
|
||||
|
||||
app.use(express.cookieParser('secret'));
|
||||
|
||||
app.use(function(req, res){
|
||||
@@ -19,7 +23,7 @@ describe('req', function(){
|
||||
app.response.cookie('obj', { foo: 'bar' }, { signed: true });
|
||||
cookieHeader = app.response.get('set-cookie');
|
||||
|
||||
val = JSON.stringify({ obj: { foo: 'bar' } });
|
||||
val = JSON.stringify({ obj: { foo: 'bar' } }, replacer, spaces);
|
||||
request(app)
|
||||
.get('/')
|
||||
.set('Cookie', cookieHeader)
|
||||
@@ -31,6 +35,10 @@ describe('req', function(){
|
||||
, cookieHeader
|
||||
, val;
|
||||
|
||||
/* So we use the same serialization for expected results. */
|
||||
var replacer = app.get('json replacer')
|
||||
, spaces = app.get('json spaces');
|
||||
|
||||
app.use(express.cookieParser('secret'));
|
||||
|
||||
app.use(function(req, res){
|
||||
@@ -41,7 +49,7 @@ describe('req', function(){
|
||||
app.response.cookie('foo', 'bar', { signed: true });
|
||||
cookieHeader = app.response.get('set-cookie');
|
||||
|
||||
val = JSON.stringify({ foo: 'bar' });
|
||||
val = JSON.stringify({ foo: 'bar' }, replacer, spaces);
|
||||
request(app)
|
||||
.get('/')
|
||||
.set('Cookie', cookieHeader)
|
||||
|
||||
@@ -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);
|
||||
})
|
||||
})
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
|
||||
var express = require('../')
|
||||
, request = require('./support/http')
|
||||
, utils = require('connect').utils
|
||||
, cookie = require('cookie');
|
||||
|
||||
describe('res', function(){
|
||||
@@ -38,7 +39,7 @@ describe('res', function(){
|
||||
done();
|
||||
})
|
||||
})
|
||||
|
||||
|
||||
it('should allow multiple calls', function(done){
|
||||
var app = express();
|
||||
|
||||
@@ -57,7 +58,7 @@ describe('res', function(){
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
|
||||
describe('.cookie(name, string, options)', function(){
|
||||
it('should set params', function(done){
|
||||
var app = express();
|
||||
@@ -75,7 +76,7 @@ describe('res', function(){
|
||||
done();
|
||||
})
|
||||
})
|
||||
|
||||
|
||||
describe('maxAge', function(){
|
||||
it('should set relative expires', function(done){
|
||||
var app = express();
|
||||
@@ -108,6 +109,25 @@ describe('res', function(){
|
||||
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(){
|
||||
@@ -144,7 +164,7 @@ describe('res', function(){
|
||||
request(app)
|
||||
.get('/')
|
||||
.end(function(err, res){
|
||||
var val = ['name=s%3Atobi.xJjV2iZ6EI7C8E5kzwbfA9PVLl1ZR07UTnuTgQQ4EnQ; Path=/'];
|
||||
var val = ['name=s%3Atobi.z6Nfs5haoP4UAqCcr497ZljiIbrNqn8EjjM10baIYvvG32lReGseC3v2T79fecY4G%2FLdEm9fpTihvlEMVuNjGw; Path=/'];
|
||||
res.headers['set-cookie'].should.eql(val);
|
||||
done();
|
||||
})
|
||||
|
||||
@@ -71,6 +71,22 @@ describe('res', function(){
|
||||
})
|
||||
})
|
||||
|
||||
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();
|
||||
|
||||
171
test/res.location.js
Normal file
171
test/res.location.js
Normal file
@@ -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();
|
||||
})
|
||||
})
|
||||
})
|
||||
})
|
||||
})
|
||||
})
|
||||
@@ -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', '/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', '/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', '/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', '/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', '/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', '/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', '/admin/login');
|
||||
done();
|
||||
})
|
||||
})
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
describe('.redirect(status, url)', function(){
|
||||
@@ -232,7 +74,7 @@ describe('res', function(){
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
|
||||
describe('when accepting html', function(){
|
||||
it('should respond with html', function(done){
|
||||
var app = express();
|
||||
@@ -268,7 +110,7 @@ describe('res', function(){
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
|
||||
describe('when accepting text', function(){
|
||||
it('should respond with text', function(done){
|
||||
var app = express();
|
||||
@@ -287,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(){
|
||||
@@ -310,4 +169,76 @@ describe('res', function(){
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
describe('responses redirected to relative paths', function(){
|
||||
function create(depth, parent) {
|
||||
var app = express();
|
||||
|
||||
if (parent) {
|
||||
parent.use('/depth' + depth, app);
|
||||
}
|
||||
|
||||
app.get('/', function(req, res){
|
||||
res.redirect('./index');
|
||||
});
|
||||
|
||||
app.get('/index', function(req, res){
|
||||
res.json({ depth: depth, content: 'index' });
|
||||
});
|
||||
|
||||
return app;
|
||||
}
|
||||
|
||||
var root = create(0);
|
||||
var depth1 = create(1, root);
|
||||
var depth2 = create(2, depth1);
|
||||
var depth3 = create(3, depth2);
|
||||
|
||||
root.use('/depth2', depth2);
|
||||
root.use('/depth3', depth3);
|
||||
|
||||
it('should not contain redundant leading slashes in the location header', function(done){
|
||||
request(root)
|
||||
.get('/')
|
||||
.end(function(err, res){
|
||||
res.headers.location.search(/^\/{2}/).should.equal(-1);
|
||||
done();
|
||||
})
|
||||
})
|
||||
|
||||
it('should preserve context when redirecting nested applications at any depth', function(done){
|
||||
request(root)
|
||||
.get('/depth1')
|
||||
.end(function(err, res){
|
||||
res.headers.should.have.property('location', '/depth1/./index');
|
||||
|
||||
request(root)
|
||||
.get('/depth1/depth2')
|
||||
.end(function(err, res){
|
||||
res.headers.should.have.property('location', '/depth1/depth2/./index');
|
||||
|
||||
request(root)
|
||||
.get('/depth1/depth2/depth3')
|
||||
.end(function(err, res){
|
||||
res.headers.should.have.property('location', '/depth1/depth2/depth3/./index');
|
||||
done();
|
||||
})
|
||||
})
|
||||
});
|
||||
})
|
||||
|
||||
it('should redirect correctly for nested applications that have been remounted', function(done){
|
||||
request(root)
|
||||
.get('/depth2')
|
||||
.end(function(err, res){
|
||||
res.headers.should.have.property('location', '/depth2/./index');
|
||||
request(root)
|
||||
.get('/depth3')
|
||||
.end(function(err, res){
|
||||
res.headers.should.have.property('location', '/depth3/./index');
|
||||
done();
|
||||
})
|
||||
})
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
@@ -206,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)
|
||||
@@ -218,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();
|
||||
})
|
||||
@@ -225,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)
|
||||
@@ -237,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();
|
||||
})
|
||||
|
||||
@@ -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:\\'));
|
||||
@@ -29,28 +49,38 @@ describe('utils.escape(html)', function(){
|
||||
})
|
||||
})
|
||||
|
||||
describe('utils.parseQuality(str)', function(){
|
||||
describe('utils.parseParams(str)', function(){
|
||||
it('should default quality to 1', function(){
|
||||
utils.parseQuality('text/html')
|
||||
.should.eql([{ value: 'text/html', quality: 1 }]);
|
||||
utils.parseParams('text/html')
|
||||
.should.eql([{ value: 'text/html', quality: 1, params: {}}]);
|
||||
})
|
||||
|
||||
it('should parse qvalues', function(){
|
||||
utils.parseQuality('text/html; q=0.5')
|
||||
.should.eql([{ value: 'text/html', quality: 0.5 }]);
|
||||
utils.parseParams('text/html; q=0.5')
|
||||
.should.eql([{ value: 'text/html', quality: 0.5, params: {}}]);
|
||||
|
||||
utils.parseQuality('text/html; q=.2')
|
||||
.should.eql([{ value: 'text/html', quality: 0.2 }]);
|
||||
utils.parseParams('text/html; q=.2')
|
||||
.should.eql([{ value: 'text/html', quality: 0.2, params: {}}]);
|
||||
})
|
||||
|
||||
|
||||
it('should parse accept parameters', function(){
|
||||
utils.parseParams('application/json; ver=2.0')
|
||||
.should.eql([{ value: 'application/json', quality: 1, params: {ver: "2.0"}}]);
|
||||
|
||||
utils.parseParams('text/html; q=0.5; level=2')
|
||||
.should.eql([{ value: 'text/html', quality: 0.5, params: {level: "2"}}]);
|
||||
utils.parseParams('text/html;q=.2;ver=beta')
|
||||
.should.eql([{ value: 'text/html', quality: 0.2, params: {ver: "beta"}}]);
|
||||
})
|
||||
|
||||
it('should work with messed up whitespace', function(){
|
||||
utils.parseQuality('text/html ; q = .2')
|
||||
.should.eql([{ value: 'text/html', quality: 0.2 }]);
|
||||
utils.parseParams('text/html ; q = .2')
|
||||
.should.eql([{ value: 'text/html', quality: 0.2, params: {}}]);
|
||||
})
|
||||
|
||||
it('should work with multiples', function(){
|
||||
var str = 'da, en;q=.5, en-gb;q=.8';
|
||||
var arr = utils.parseQuality(str);
|
||||
var arr = utils.parseParams(str);
|
||||
arr[0].value.should.equal('da');
|
||||
arr[1].value.should.equal('en-gb');
|
||||
arr[2].value.should.equal('en');
|
||||
@@ -58,7 +88,7 @@ describe('utils.parseQuality(str)', function(){
|
||||
|
||||
it('should sort by quality', function(){
|
||||
var str = 'text/plain;q=.2, application/json, text/html;q=0.5';
|
||||
var arr = utils.parseQuality(str);
|
||||
var arr = utils.parseParams(str);
|
||||
arr[0].value.should.equal('application/json');
|
||||
arr[1].value.should.equal('text/html');
|
||||
arr[2].value.should.equal('text/plain');
|
||||
@@ -66,7 +96,7 @@ describe('utils.parseQuality(str)', function(){
|
||||
|
||||
it('should exclude those with a quality of 0', function(){
|
||||
var str = 'text/plain;q=.2, application/json, text/html;q=0';
|
||||
var arr = utils.parseQuality(str);
|
||||
var arr = utils.parseParams(str);
|
||||
arr.should.have.length(2);
|
||||
})
|
||||
})
|
||||
|
||||
Reference in New Issue
Block a user