Compare commits

...

144 Commits
3.4.0 ... 3.7.0

Author SHA1 Message Date
Douglas Christopher Wilson
b91cd66fc5 3.7.0 2014-05-18 10:40:13 -04:00
Douglas Christopher Wilson
787d630157 update should to 3.3.1 2014-05-18 10:38:42 -04:00
Douglas Christopher Wilson
1f938c560a tests: improve examples/auth tests 2014-05-18 01:54:05 -04:00
Douglas Christopher Wilson
a96924a555 build: remove lib-cov fork 2014-05-18 01:35:12 -04:00
Douglas Christopher Wilson
33dc6629ff update connect to 2.16.2 2014-05-18 01:30:44 -04:00
Douglas Christopher Wilson
1b3fb0af8c build: add coverage reporting 2014-05-18 01:25:15 -04:00
Douglas Christopher Wilson
12da523ff7 build: test coverage with istanbul 2014-05-18 01:23:15 -04:00
Douglas Christopher Wilson
0f49d80623 build: clean up package file 2014-05-18 01:16:38 -04:00
Douglas Christopher Wilson
1717516a78 build: improve platform portability 2014-05-18 01:14:45 -04:00
Jonathan Ong
328c6d3060 remove unnecessary test/support/http
backport of 643397ed21
2014-05-18 00:57:54 -04:00
Douglas Christopher Wilson
566720be15 improve proxy trust with ip address list
closes #2099
2014-05-17 20:02:20 -04:00
Douglas Christopher Wilson
65f13c3cc6 update connect to 2.16.1 2014-05-17 14:30:52 -04:00
Douglas Christopher Wilson
d98e2e7498 deprecation messages are bright red on TTYs 2014-05-13 17:06:45 -04:00
Douglas Christopher Wilson
f7be983a77 3.6.0 2014-05-09 17:03:23 -04:00
Douglas Christopher Wilson
a2553126dd support PURGE method 2014-05-09 10:19:20 -04:00
Douglas Christopher Wilson
0639c45acd build: add soft testing on node.js 0.11 2014-05-09 01:03:35 -04:00
Douglas Christopher Wilson
920f46ad65 tests: add more res.jsonp? tests 2014-05-08 21:27:01 -04:00
Douglas Christopher Wilson
35a66d8a14 tests: add test for res.format in route
closes #2016
2014-05-08 21:15:48 -04:00
Douglas Christopher Wilson
4e1e252e17 deprecate res.json(obj, status)
closes #2106
closes #2107
2014-05-08 21:11:05 -04:00
Douglas Christopher Wilson
0461e55380 deprecate app.del
closes #2095
2014-05-08 19:16:25 -04:00
Douglas Christopher Wilson
8dc4ff26f9 Add standard deprecation utility
* deprecations ignore when NODE_ENV=test
 * uses node.js util.deprecate
2014-05-08 19:01:16 -04:00
Roman Shtylman
6f9e927633 remove deprecation message about passing path as array
backport commit 6b19e3dc0a
2014-05-08 18:09:25 -04:00
Oliver Salzburg
40a43eb753 Value parameter of app.set() is now typed optional mixed 2014-05-08 17:04:14 -04:00
Douglas Christopher Wilson
a8bb4bab2b tests: add test for app.delete 2014-05-08 16:40:28 -04:00
Douglas Christopher Wilson
417999884b update supertest to 0.12.0 2014-05-08 16:29:41 -04:00
Douglas Christopher Wilson
17a739e35f update mkdirp to 0.5.0 2014-05-08 16:25:06 -04:00
Douglas Christopher Wilson
66b38b58bc Merge branch '3.5.x' into 3.x 2014-05-08 13:55:00 -04:00
Douglas Christopher Wilson
dc31ea34b8 3.5.3 2014-05-08 13:51:26 -04:00
Douglas Christopher Wilson
d58ca520c8 Fix res.jsonp error if callback param is object
fixes #2104
2014-05-08 13:42:19 -04:00
Douglas Christopher Wilson
4b646c2f8d docs: update core contributors 2014-05-07 23:08:55 -04:00
Douglas Christopher Wilson
35757ed1f5 docs: add NPM badge 2014-05-07 22:59:12 -04:00
Douglas Christopher Wilson
fed0d5df5c docs: use SVG badges 2014-05-07 22:57:05 -04:00
Douglas Christopher Wilson
c99fa6a192 Fix req.host for IPv6 literals
fixes #2102
2014-05-07 14:08:08 -04:00
Douglas Christopher Wilson
0d468cbe6c update history 2014-05-05 00:42:50 -04:00
Douglas Christopher Wilson
f92ba6d0cf update connect to 2.15.0 2014-05-05 00:35:43 -04:00
Douglas Christopher Wilson
0408e3727e deps: debug@^0.8.0 2014-05-02 17:02:28 -04:00
Douglas Christopher Wilson
d5815922ca 3.5.2 2014-04-24 16:36:37 -04:00
Douglas Christopher Wilson
972c01afc9 update supertest to 0.11.0 2014-04-24 16:30:58 -04:00
Douglas Christopher Wilson
8894e30869 Skip publishing benchmarks dir to npm 2014-04-24 16:27:00 -04:00
Douglas Christopher Wilson
5d8dba5fe0 update mocha to 1.18.2 2014-04-24 16:23:58 -04:00
Douglas Christopher Wilson
90fbc1a33e update cookie to 0.1.2 2014-04-24 16:21:22 -04:00
Douglas Christopher Wilson
55dea47b94 update mkdirp to 0.4.0 2014-04-24 16:20:31 -04:00
Douglas Christopher Wilson
c7791a207b update send to 0.3.0
fixes #2024
closes #2071
closes #2072
2014-04-24 15:50:55 -04:00
Douglas Christopher Wilson
30d18888b9 update connect to 2.14.5 2014-04-24 15:50:54 -04:00
Roman Shtylman
df50669092 3.5.1 2014-03-25 16:56:54 -04:00
Roman Shtylman
abd6b7c5c3 pin down less-middleware
Things are broken in 0.2 version of less-middleware so use 0.1 line
2014-03-25 16:55:57 -04:00
Jonathan Ong
87912103c9 3.5.0 2014-03-06 14:57:30 -08:00
Jonathan Ong
4ce1ee458e bump deps 2014-03-06 14:57:05 -08:00
Roman Shtylman
8aff64f89a backport dependency updates
- range parser 1.0.0
- fresh 0.2.1
- send 0.2.0
- cookie-signature 1.0.3
- merge-descriptors 0.0.2
2014-01-29 20:06:38 -05:00
Jonathan Ong
ff23423d34 3.4.8 2014-01-13 20:50:51 -08:00
Doug Patti
1d97599f8b prevent incorrect automatic OPTIONS responses
The router has automatic handling of OPTIONS based on the registered
routes, but if you make an OPTIONS request for an endpoint that does
not exist, then it will still return a 200 with nothing allowed.
Instead, we can let the request move on down the middleware chain. This
has two benefits: first, if the route was not defined and no other
middleware handles it, it will return with a 404. Secondly, if multiple
routers are used and a later one has the route or a custom OPTIONS
defined, the first router will not respond incorrectly.
2014-01-13 20:46:07 -08:00
Matheus Azzi
e465624fd0 Update layout.jade 2014-01-13 20:45:50 -08:00
TJ Holowaychuk
dc5932d177 Merge pull request #1877 from reqshark/master
update express jade layout generator
2013-12-23 10:34:47 -08:00
Bent Cardan
cfd93b7529 update express jade layout generator
update doctype
2013-12-23 13:03:21 -05:00
Jonathan Ong
8b2208f394 Merge pull request #1876 from yosssi/dev
Updated the example file to use `doctype html` on  because  `doctype 5` was deprecated on Jade version 1.0.0.
2013-12-23 08:10:26 -08:00
yosssi
00a3b01f39 Changed doctype 5 to doctype html on the example file because the former was deprecated on Jade version 1.0.0. 2013-12-23 22:13:05 +09:00
TJ Holowaychuk
3baca251f0 use 8 threads for benchmarks 2013-12-22 08:57:04 -08:00
TJ Holowaychuk
72daae1d92 Merge pull request #1869 from yamatt/master
Error message now describes where the view was not able to be found.
2013-12-21 11:13:04 -08:00
Matt Copperwaite
fcbe53ddb5 Added appropriate test for more descriptive render error 2013-12-21 17:34:59 +00:00
Jonathan Ong
e9851672eb bench: remove --harmony-generators flag 2013-12-20 21:15:17 -08:00
TJ Holowaychuk
9a45f7bd3d add new benchmarks (to match koa) 2013-12-20 19:34:59 -08:00
Matt Copperwaite
85834fd146 Error message now describes where the view was not able to be found. Useful for debugging. 2013-12-20 11:39:31 +00:00
Roman Shtylman
a0c1ac7b45 add license field to package.json
close #1862
2013-12-18 10:16:56 -05:00
Alex Kocharin
7b0dca0f9c throw 400 in case of malformed paths 2013-12-11 17:14:44 -08:00
Jonathan Ong
34c83d7d29 3.4.7 2013-12-10 23:57:39 -08:00
Jonathan Ong
7c6882234e bump connect, mocha, and should 2013-12-10 23:54:07 -08:00
Jonathan Ong
2e68ddbae9 expose connect.middleware using Object.getOwnPropertyDescriptor()
closes #1853. no tests, but it should be fine.
2013-12-10 23:52:48 -08:00
Jonathan Ong
7724fc6af7 3.4.6 2013-12-01 12:21:08 -08:00
Roman Shtylman
2939075f03 Merge pull request #1836 from fluxusfrequency/patch-1
Grammar and punctuation fixes [ci skip]
2013-11-28 08:18:42 -08:00
Ben Lewis
606f68de02 Grammar and punctuation fixes [ci skip] 2013-11-28 06:36:21 -07:00
Jonathan Ong
863160ae49 3.4.5 2013-11-27 15:54:41 -08:00
TJ Holowaychuk
edd39fb194 fix weird variable name in example 2013-11-26 23:39:35 -08:00
TJ Holowaychuk
a71d264d45 fix weird variable name in example 2013-11-26 23:39:08 -08:00
TJ Holowaychuk
8a7a695836 ocd 2013-11-26 11:12:56 -08:00
TJ Holowaychuk
de54af4061 Merge pull request #1829 from michaelficarra/patch-1
fixes #1826: res.redirect('toString') fails with 500
2013-11-26 11:12:13 -08:00
Michael Ficarra
2f2a652bc9 fixes #1826: res.redirect('toString') fails with 500
Removed the unused map and corrected the doc comment.
2013-11-26 13:11:15 -06:00
TJ Holowaychuk
1e638663de Merge pull request #1822 from yakubori/auth-buffer-call-removal
Removed Buffer call with 'binary' encoding option in auth example.
2013-11-21 12:32:39 -08:00
Rick Yakubowski
1684a8792a Removed Buffer call with 'binary' encoding option in auth example.
According to the Node.js documentation for Buffer objects regarding the
'binary' encoding option:

"This encoding method is deprecated and should be avoided in favor of
Buffer objects where possible. This encoding will be removed in future
versions of Node."

Simply calling toString() with a 'base64' argument on the hash seems to
accomplish the same thing; this makes the code compatible with current
documentation as well as being a bit easier to follow.
2013-11-21 14:01:56 -05:00
Roman Shtylman
f47c0d9774 add Router.all() method
Similar to app.all() but specifically for attaching handlers to all
methods under a standalone router. This is useful for isolating routers
that require "middleware" like features for all routes managed by the
router.
2013-11-19 18:52:04 -05:00
Roman Shtylman
89e7264e53 pin marked devDep to protect out tests
marked has shown that it cannot be trusted with patch level changes!
2013-11-09 22:31:17 -05:00
Roman Shtylman
cada9f61c8 pin devDependencies using ~
If tests are passing and everything works, don't let things change out
from under us as much. Really we should do hard pinning, but will be a
bit lenient for now.
2013-11-09 22:26:09 -05:00
Jonathan Ong
373fa55981 fix markdown example test
marked 0.2.10 adds ids to header elements now.
2013-11-09 19:08:25 -08:00
Jonathan Ong
2bc703cfc2 Merge pull request #1802 from kapouer/patch-1
Remove leading ./ when using res.location('./relative')
2013-11-02 15:09:30 -07:00
Jérémy Lal
c9865b821d Test location with leading ./ and containing .. 2013-11-02 02:28:54 +01:00
Jérémy Lal
9c0de23645 Update tests expectancy of location headers 2013-11-02 02:28:49 +01:00
Jérémy Lal
b7a38af41d Use url.resolve to compute location header of relative paths 2013-11-02 02:28:29 +01:00
Jérémy Lal
661914781e semicolons 2013-11-02 00:39:32 +01:00
Jonathan Ong
6e3f3887e9 pin deps using semver1
somebody is going to complain that they can't install stuff because
they haven't upgraded npm
2013-10-30 20:55:11 -07:00
Jonathan Ong
a66d6bb034 pin dev deps to semver compatible versions 2013-10-30 20:51:10 -07:00
Jonathan Ong
2e197e2b98 be less picky with ENOENT errors in tests
closes #1580
2013-10-30 20:37:01 -07:00
Jonathan Ong
55d1a4f964 always send ETag when content-length > 0
closes #1780
2013-10-30 20:34:16 -07:00
Jonathan Ong
82a7d7a977 no semver2 so travis stops crying 2013-10-29 22:44:01 -07:00
Jonathan Ong
dae54b456f 3.4.4 2013-10-29 10:33:32 -07:00
Jonathan Ong
1b7a044f33 bump connect 2013-10-29 10:30:26 -07:00
Jonathan Ong
18264403b1 bump supertest to 0.8.1 2013-10-28 15:24:48 -07:00
Jonathan Ong
04d43b7039 remove .gitmodules
it's empty
2013-10-28 14:38:46 -07:00
TJ Holowaychuk
2dfecfb661 update methods for SEARCH 2013-10-28 12:02:24 -07:00
Jonathan Ong
250f1f5f6e Merge pull request #1796 from malixsys/patch-1
2013-100-23 -> 2013-10-23
2013-10-25 10:59:48 -07:00
M Alix
3ac718763f 2013-100-23 -> 2013-10-23 2013-10-25 14:28:24 +02:00
Jonathan Ong
05e1555c0d Merge pull request #1795 from chirag04/master
replace bodyparser with json and urlencoded
2013-10-25 03:31:24 -07:00
chirag04
855d1e2bf5 replace bodyparser with json and urlencoded 2013-10-25 15:45:25 +05:30
Jonathan Ong
f0bfb3b2b2 3.4.3 2013-10-23 11:19:48 -07:00
Jonathan Ong
4b4db0f7fb 3.4.2 2013-10-18 19:03:41 -07:00
Jonathan Ong
9bed2b80ee lint: remove unused stuff 2013-10-18 01:18:56 -07:00
Jonathan Ong
bb157c0cbf replace old contributors info with github's contributors 2013-10-17 13:06:13 -07:00
Jonathan Ong
1ef05d4a28 downgrade commander. closes #1783 2013-10-17 12:57:39 -07:00
TJ Holowaychuk
0b88208022 Merge branch 'master' of github.com:visionmedia/express 2013-10-16 19:52:00 -07:00
TJ Holowaychuk
c9d9ed3493 fix res.sendfile() callback
what the hell... I was just told readable streams have finish not end,
make up your mind node!
2013-10-17 02:51:01 +00:00
TJ Holowaychuk
bd8b9f5781 Merge branch 'master' of github.com:visionmedia/express 2013-10-16 19:21:09 -07:00
TJ Holowaychuk
9cbcf23df0 docs 2013-10-16 19:17:49 -07:00
Jonathan Ong
36e42db05b mocha globals - readable-stream defines globals
isaac you bastard
2013-10-15 18:33:47 -07:00
Jonathan Ong
2bf6a1d813 3.4.1 2013-10-15 18:28:49 -07:00
Jonathan Ong
e8373d3564 Merge pull request #1779 from visionmedia/jsonp-typeof-callback
check existence of jsonp callback
2013-10-15 18:22:01 -07:00
Jonathan Ong
e218377a3d check existence of jsonp callback 2013-10-15 12:39:32 -07:00
Jonathan Ong
7d1aed4955 update commander. closes #1693
i hope this doesn't break anything
2013-10-14 21:22:19 -07:00
Jonathan Ong
b4acbcf1fe use path.join for 'views' setting. closes #1427 2013-10-14 21:16:57 -07:00
Jonathan Ong
50cb62c5d2 fix tests for should.js 2013-10-14 18:35:46 -07:00
Jonathan Ong
4cf868bd74 Merge pull request #1776 from ykumar6/master
Add Runnable.com button
2013-10-14 18:33:34 -07:00
Yash Kumar
baa5a7c3e9 Add Runnable.com button 2013-10-14 14:16:18 -07:00
Jonathan Ong
ee228f7aea Merge pull request #1759 from muratgu/patch-1
fixes #1600
2013-09-19 12:43:42 -07:00
Jonathan Ong
d5b11c7d1b Merge pull request #1760 from jseip1679/master
documentation language fix
2013-09-19 12:38:21 -07:00
Jake Seip
ed7db34bab documentation language fix 2013-09-19 10:41:45 -07:00
muratgu
57e45e3af8 fixes #1600 2013-09-19 10:27:21 -07:00
Jonathan Ong
1dc46478cb README: add more links to expressjs.com 2013-09-17 00:35:23 -07:00
TJ Holowaychuk
113ed0927d fix test label typo 2013-09-16 23:34:16 +00:00
TJ Holowaychuk
ab8be2d741 remove second signed cookie test
for now
2013-09-16 23:33:42 +00:00
TJ Holowaychuk
3b53b11fcd fix signed cookies test 2013-09-16 23:32:34 +00:00
TJ Holowaychuk
9fb661559b refactor signed cookie tests 2013-09-16 23:24:54 +00:00
Jonathan Ong
04882cf72c Merge pull request #1735 from lxe/malformed-capture-route
Wrapped encodeURIcomponent in try-catch to eliminate errors on malformed captures.
2013-09-16 15:32:57 -07:00
lxe
288176bbc9 Added safe encodeURIcomponent to eliminate errors on malformed captures. 2013-09-16 14:57:31 -04:00
Jonathan Ong
5638a4fc62 Merge pull request #1688 from menzoic/issue/menzoic-1
removed unnecessary require statement
2013-09-09 21:45:19 -07:00
TJ Holowaychuk
3b4ce91fa3 refactor res.format() with a little ocd 2013-09-08 09:30:59 -07:00
TJ Holowaychuk
1c87e5e9a8 Merge pull request #1747 from sorribas/master
res.format() now includes charset.
2013-09-08 09:30:23 -07:00
Eduardo Sorribas
a887e6a881 Minor refactor of res.format 2013-09-08 02:34:52 -04:00
Eduardo Sorribas
69290cad6f res.format() now includes charset. Fixes #1744 2013-09-08 02:10:46 -04:00
Jonathan Ong
b66c7da05f Merge pull request #1659 from dresende/patch-1
Fixes typo in index.js vhost example
2013-09-07 21:43:45 -07:00
Jonathan Ong
92ddf77453 Merge pull request #1729 from patelatharva/patch-1
Improved variable names and updated comments for better clarity of example
2013-09-07 21:43:06 -07:00
TJ Holowaychuk
8e2f538983 refactor res.links() 2013-09-07 15:26:12 -07:00
TJ Holowaychuk
2817d8caf2 Merge pull request #1746 from sorribas/master
Allow multiple call concatenation for res.links.
2013-09-07 15:24:50 -07:00
Eduardo Sorribas
09bede1a92 Fix the links test so it resets the header for each test. 2013-09-07 01:10:13 -04:00
Eduardo Sorribas
7059d3b71e Allow multiple call concatenation for res.links. Fixes #1683 2013-09-06 21:44:03 -04:00
Atharva
058d7ec2ea Improved variable names and updated comments for better clarity of example 2013-08-24 16:44:44 +05:30
Esco Obong
7c2ed1d2d6 removed unnecessary require statement 2013-07-15 02:13:32 -04:00
Diogo Resende
7a31a1d311 Fixes typo in index.js vhost example 2013-06-23 23:23:58 +02:00
102 changed files with 1259 additions and 554 deletions

5
.gitignore vendored
View File

@@ -1,6 +1,5 @@
coverage.html
coverage/
.DS_Store
lib-cov
*.seed
*.log
*.csv
@@ -13,7 +12,5 @@ benchmarks/graphs
testing
node_modules/
testing
.coverage_data
cover_html
test.js
.idea

0
.gitmodules vendored
View File

View File

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

View File

@@ -2,3 +2,9 @@ language: node_js
node_js:
- "0.8"
- "0.10"
- "0.11"
matrix:
allow_failures:
- node_js: "0.11"
fast_finish: true
script: "npm run-script test-travis"

View File

@@ -1,49 +1,183 @@
3.7.0 / 2014-05-18
==================
3.4.0 / 2013-09-07
* proper proxy trust with `app.set('trust proxy', trust)`
- `app.set('trust proxy', 1)` trust first hop
- `app.set('trust proxy', 'loopback')` trust loopback addresses
- `app.set('trust proxy', '10.0.0.1')` trust single IP
- `app.set('trust proxy', '10.0.0.1/16')` trust subnet
- `app.set('trust proxy', '10.0.0.1, 10.0.0.2')` trust list
- `app.set('trust proxy', false)` turn off
- `app.set('trust proxy', true)` trust everything
* update connect to 2.16.2
- deprecate `res.headerSent` -- use `res.headersSent`
- deprecate `res.on("header")` -- use on-headers module instead
- fix edge-case in `res.appendHeader` that would append in wrong order
- json: use body-parser
- urlencoded: use body-parser
- dep: bytes@1.0.0
- dep: cookie-parser@1.1.0
- dep: csurf@1.2.0
- dep: express-session@1.1.0
- dep: method-override@1.0.1
3.6.0 / 2014-05-09
==================
* deprecate `app.del()` -- use `app.delete()` instead
* deprecate `res.json(obj, status)` -- use `res.json(status, obj)` instead
- the edge-case `res.json(status, num)` requires `res.status(status).json(num)`
* deprecate `res.jsonp(obj, status)` -- use `res.jsonp(status, obj)` instead
- the edge-case `res.jsonp(status, num)` requires `res.status(status).jsonp(num)`
* support PURGE method
- add `app.purge`
- add `router.purge`
- include PURGE in `app.all`
* update connect to 2.15.0
* Add `res.appendHeader`
* Call error stack even when response has been sent
* Patch `res.headerSent` to return Boolean
* Patch `res.headersSent` for node.js 0.8
* Prevent default 404 handler after response sent
* dep: compression@1.0.2
* dep: connect-timeout@1.1.0
* dep: debug@^0.8.0
* dep: errorhandler@1.0.1
* dep: express-session@1.0.4
* dep: morgan@1.0.1
* dep: serve-favicon@2.0.0
* dep: serve-index@1.0.2
* update debug to 0.8.0
* add `enable()` method
* change from stderr to stdout
* update methods to 1.0.0
- add PURGE
* update mkdirp to 0.5.0
3.5.3 / 2014-05-08
==================
* fix `req.host` for IPv6 literals
* fix `res.jsonp` error if callback param is object
3.5.2 / 2014-04-24
==================
* update connect to 2.14.5
* update cookie to 0.1.2
* update mkdirp to 0.4.0
* update send to 0.3.0
3.5.1 / 2014-03-25
==================
* pin less-middleware in generated app
3.5.0 / 2014-03-06
==================
* bump deps
3.4.8 / 2014-01-13
==================
* prevent incorrect automatic OPTIONS responses #1868 @dpatti
* update binary and examples for jade 1.0 #1876 @yossi, #1877 @reqshark, #1892 @matheusazzi
* throw 400 in case of malformed paths @rlidwka
3.4.7 / 2013-12-10
==================
* update connect
3.4.6 / 2013-12-01
==================
* update connect (raw-body)
3.4.5 / 2013-11-27
==================
* update connect
* res.location: remove leading ./ #1802 @kapouer
* res.redirect: fix `res.redirect('toString') #1829 @michaelficarra
* res.send: always send ETag when content-length > 0
* router: add Router.all() method
3.4.4 / 2013-10-29
==================
* update connect
* update supertest
* update methods
* express(1): replace bodyParser() with urlencoded() and json() #1795 @chirag04
3.4.3 / 2013-10-23
==================
* update connect
3.4.2 / 2013-10-18
==================
* update connect
* downgrade commander
3.4.1 / 2013-10-15
==================
* update connect
* update commander
* jsonp: check if callback is a function
* router: wrap encodeURIComponent in a try/catch #1735 (@lxe)
* res.format: now includes chraset @1747 (@sorribas)
* res.links: allow multiple calls @1746 (@sorribas)
3.4.0 / 2013-09-07
==================
* add res.vary(). Closes #1682
* update connect
3.3.8 / 2013-09-02
3.3.8 / 2013-09-02
==================
* update connect
3.3.7 / 2013-08-28
3.3.7 / 2013-08-28
==================
* update connect
3.3.6 / 2013-08-27
3.3.6 / 2013-08-27
==================
* Revert "remove charset from json responses. Closes #1631" (causes issues in some clients)
* add: req.accepts take an argument list
3.3.4 / 2013-07-08
3.3.4 / 2013-07-08
==================
* update send and connect
3.3.3 / 2013-07-04
3.3.3 / 2013-07-04
==================
* update connect
3.3.2 / 2013-07-03
3.3.2 / 2013-07-03
==================
* update connect
* update send
* remove .version export
3.3.1 / 2013-06-27
3.3.1 / 2013-06-27
==================
* update connect
3.3.0 / 2013-06-26
3.3.0 / 2013-06-26
==================
* update connect
@@ -52,12 +186,12 @@
* change: return actual booleans from req.accept* functions
* fix jsonp callback array throw
3.2.6 / 2013-06-02
3.2.6 / 2013-06-02
==================
* update connect
3.2.5 / 2013-05-21
3.2.5 / 2013-05-21
==================
* update connect
@@ -65,23 +199,23 @@
* add: throw a meaningful error when there is no default engine
* change generation of ETags with res.send() to GET requests only. Closes #1619
3.2.4 / 2013-05-09
3.2.4 / 2013-05-09
==================
* fix `req.subdomains` when no Host is present
* fix `req.host` when no Host is present, return undefined
3.2.3 / 2013-05-07
3.2.3 / 2013-05-07
==================
* update connect / qs
3.2.2 / 2013-05-03
3.2.2 / 2013-05-03
==================
* update qs
3.2.1 / 2013-04-29
3.2.1 / 2013-04-29
==================
* add app.VERB() paths array deprecation warning
@@ -89,27 +223,27 @@
* update qs and remove all ~ semver crap
* fix: accept number as value of Signed Cookie
3.2.0 / 2013-04-15
3.2.0 / 2013-04-15
==================
* add "view" constructor setting to override view behaviour
* add req.acceptsEncoding(name)
* add req.acceptedEncodings
* revert cookie signature change causing session race conditions
* fix sorting of Accept values of the same quality
* fix sorting of Accept values of the same quality
3.1.2 / 2013-04-12
3.1.2 / 2013-04-12
==================
* add support for custom Accept parameters
* update cookie-signature
3.1.1 / 2013-04-01
3.1.1 / 2013-04-01
==================
* add X-Forwarded-Host support to `req.host`
* fix relative redirects
* update mkdirp
* fix relative redirects
* update mkdirp
* update buffer-crc32
* remove legacy app.configure() method from app template.

View File

@@ -1,33 +0,0 @@
MOCHA_OPTS= --check-leaks
REPORTER = dot
check: test
test: test-unit test-acceptance
test-unit:
@NODE_ENV=test ./node_modules/.bin/mocha \
--reporter $(REPORTER) \
$(MOCHA_OPTS)
test-acceptance:
@NODE_ENV=test ./node_modules/.bin/mocha \
--reporter $(REPORTER) \
--bail \
test/acceptance/*.js
test-cov: lib-cov
@EXPRESS_COV=1 $(MAKE) test REPORTER=html-cov > coverage.html
lib-cov:
@jscoverage lib lib-cov
benchmark:
@./support/bench
clean:
rm -f coverage.html
rm -fr lib-cov
.PHONY: test test-unit test-acceptance benchmark clean

View File

@@ -1,6 +1,8 @@
![express logo](http://f.cl.ly/items/0V2S1n0K1i3y1c122g04/Screen%20Shot%202012-04-11%20at%209.59.42%20AM.png)
[![express logo](http://f.cl.ly/items/0V2S1n0K1i3y1c122g04/Screen%20Shot%202012-04-11%20at%209.59.42%20AM.png)](http://expressjs.com/)
Fast, unopinionated, minimalist web framework for [node](http://nodejs.org). [![Build Status](https://secure.travis-ci.org/visionmedia/express.png)](http://travis-ci.org/visionmedia/express)
Fast, unopinionated, minimalist web framework for [node](http://nodejs.org).
[![NPM version](https://badge.fury.io/js/express.svg)](http://badge.fury.io/js/express) [![Build Status](https://travis-ci.org/visionmedia/express.svg?branch=master)](https://travis-ci.org/visionmedia/express) [![Coverage Status](https://img.shields.io/coveralls/visionmedia/express.svg)](https://coveralls.io/r/visionmedia/express) [![Gittip](http://img.shields.io/gittip/visionmedia.svg)](https://www.gittip.com/visionmedia/)
```js
var express = require('express');
@@ -48,18 +50,19 @@ app.listen(3000);
## Philosophy
The Express philosophy is to provide small, robust tooling for HTTP servers. Making
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
Built on Connect, you can use _only_ what you need, and nothing more. Applications
can be as big or as small as you like, even a single file. Express does
not force you to use any specific ORM or template engine. With support for over
14 template engines via [Consolidate.js](http://github.com/visionmedia/consolidate.js)
14 template engines via [Consolidate.js](http://github.com/visionmedia/consolidate.js),
you can quickly craft your perfect framework.
## More Information
* [Website and Documentation](http://expressjs.com/) stored at [visionmedia/expressjs.com](https://github.com/visionmedia/expressjs.com)
* Join #express on freenode
* [Google Group](http://groups.google.com/group/express-js) for discussion
* Follow [tjholowaychuk](http://twitter.com/tjholowaychuk) on twitter for updates
@@ -69,89 +72,35 @@ app.listen(3000);
## Viewing Examples
Clone the Express repo, then 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 dependencies:
$ git clone git://github.com/visionmedia/express.git --depth 1
$ cd express
$ npm install
then run whichever tests you want:
Then run whichever tests you want:
$ node examples/content-negotiation
You can also view live examples here:
<a href="https://runnable.com/express" target="_blank"><img src="https://runnable.com/external/styles/assets/runnablebtn.png" style="width:67px;height:25px;"></a>
## Running Tests
To run the test suite first invoke the following command within the repo, installing the development dependencies:
To run the test suite, first invoke the following command within the repo, installing the development dependencies:
$ npm install
then run the tests:
Then run the tests:
$ make test
```sh
$ npm test
```
## Contributors
```
project: express
commits: 3559
active : 468 days
files : 237
authors:
1891 Tj Holowaychuk 53.1%
1285 visionmedia 36.1%
182 TJ Holowaychuk 5.1%
54 Aaron Heckmann 1.5%
34 csausdev 1.0%
26 ciaranj 0.7%
21 Robert Sköld 0.6%
6 Guillermo Rauch 0.2%
3 Dav Glass 0.1%
3 Nick Poulden 0.1%
2 Randy Merrill 0.1%
2 Benny Wong 0.1%
2 Hunter Loftis 0.1%
2 Jake Gordon 0.1%
2 Brian McKinney 0.1%
2 Roman Shtylman 0.1%
2 Ben Weaver 0.1%
2 Dave Hoover 0.1%
2 Eivind Fjeldstad 0.1%
2 Daniel Shaw 0.1%
1 Matt Colyer 0.0%
1 Pau Ramon 0.0%
1 Pero Pejovic 0.0%
1 Peter Rekdal Sunde 0.0%
1 Raynos 0.0%
1 Teng Siong Ong 0.0%
1 Viktor Kelemen 0.0%
1 ctide 0.0%
1 8bitDesigner 0.0%
1 isaacs 0.0%
1 mgutz 0.0%
1 pikeas 0.0%
1 shuwatto 0.0%
1 tstrimple 0.0%
1 ewoudj 0.0%
1 Adam Sanderson 0.0%
1 Andrii Kostenko 0.0%
1 Andy Hiew 0.0%
1 Arpad Borsos 0.0%
1 Ashwin Purohit 0.0%
1 Benjen 0.0%
1 Darren Torpey 0.0%
1 Greg Ritter 0.0%
1 Gregory Ritter 0.0%
1 James Herdman 0.0%
1 Jim Snodgrass 0.0%
1 Joe McCann 0.0%
1 Jonathan Dumaine 0.0%
1 Jonathan Palardy 0.0%
1 Jonathan Zacsh 0.0%
1 Justin Lilly 0.0%
1 Ken Sato 0.0%
1 Maciej Małecki 0.0%
1 Masahiro Hayashi 0.0%
```
https://github.com/visionmedia/express/graphs/contributors
## License

13
benchmarks/Makefile Normal file
View File

@@ -0,0 +1,13 @@
all:
@./run 1 middleware
@./run 5 middleware
@./run 10 middleware
@./run 15 middleware
@./run 20 middleware
@./run 30 middleware
@./run 50 middleware
@./run 100 middleware
@echo
.PHONY: all

23
benchmarks/middleware.js Normal file
View File

@@ -0,0 +1,23 @@
var http = require('http');
var express = require('..');
var app = express();
// number of middleware
var n = parseInt(process.env.MW || '1', 10);
console.log(' %s middleware', n);
while (n--) {
app.use(function(req, res, next){
next();
});
}
var body = new Buffer('Hello World');
app.use(function(req, res, next){
res.send(body);
});
app.listen(3333);

16
benchmarks/run Executable file
View File

@@ -0,0 +1,16 @@
#!/usr/bin/env bash
echo
MW=$1 node $2 &
pid=$!
sleep 2
wrk 'http://localhost:3333/?foo[bar]=baz' \
-d 3 \
-c 50 \
-t 8 \
| grep 'Requests/sec' \
| awk '{ print " " $2 }'
kill $pid

View File

@@ -4,8 +4,7 @@
* Module dependencies.
*/
var exec = require('child_process').exec
, program = require('commander')
var program = require('commander')
, mkdirp = require('mkdirp')
, pkg = require('../package.json')
, version = pkg.version
@@ -75,7 +74,7 @@ var users = [
*/
var jadeLayout = [
'doctype 5'
'doctype html'
, 'html'
, ' head'
, ' title= title'
@@ -219,11 +218,12 @@ var app = [
, ''
, '// all environments'
, 'app.set(\'port\', process.env.PORT || 3000);'
, 'app.set(\'views\', __dirname + \'/views\');'
, 'app.set(\'views\', path.join(__dirname, \'views\'));'
, 'app.set(\'view engine\', \':TEMPLATE\');'
, 'app.use(express.favicon());'
, 'app.use(express.logger(\'dev\'));'
, 'app.use(express.bodyParser());'
, 'app.use(express.json());'
, 'app.use(express.urlencoded());'
, 'app.use(express.methodOverride());{sess}'
, 'app.use(app.router);{css}'
, 'app.use(express.static(path.join(__dirname, \'public\')));'
@@ -324,10 +324,10 @@ function createApplicationAt(path) {
// CSS Engine support
switch (program.css) {
case 'less':
app = app.replace('{css}', eol + 'app.use(require(\'less-middleware\')({ src: __dirname + \'/public\' }));');
app = app.replace('{css}', eol + 'app.use(require(\'less-middleware\')({ src: path.join(__dirname, \'public\') }));');
break;
case 'stylus':
app = app.replace('{css}', eol + 'app.use(require(\'stylus\').middleware(__dirname + \'/public\'));');
app = app.replace('{css}', eol + 'app.use(require(\'stylus\').middleware(path.join(__dirname, \'public\')));');
break;
default:
app = app.replace('{css}', '');
@@ -357,7 +357,7 @@ function createApplicationAt(path) {
// CSS Engine support
switch (program.css) {
case 'less':
pkg.dependencies['less-middleware'] = '*';
pkg.dependencies['less-middleware'] = '~0.1.15';
break;
default:
if (program.css) {

View File

@@ -32,7 +32,7 @@ var iterations = 12000;
exports.hash = function (pwd, salt, fn) {
if (3 == arguments.length) {
crypto.pbkdf2(pwd, salt, iterations, len, function(err, hash){
fn(err, (new Buffer(hash, 'binary')).toString('base64'));
fn(err, hash.toString('base64'));
});
} else {
fn = salt;
@@ -41,8 +41,8 @@ exports.hash = function (pwd, salt, fn) {
salt = salt.toString('base64');
crypto.pbkdf2(pwd, salt, iterations, len, function(err, hash){
if (err) return fn(err);
fn(null, salt, (new Buffer(hash, 'binary')).toString('base64'));
fn(null, salt, hash.toString('base64'));
});
});
}
};
};

View File

@@ -1,8 +1,9 @@
var express = require('../../')
, app = module.exports = express()
, users = require('./db');
// so either you can deal with different types of formatting
// for expected response in index.js
app.get('/', function(req, res){
res.format({
html: function(){
@@ -24,10 +25,11 @@ app.get('/', function(req, res){
});
// or you could write a tiny middleware like
// this to abstract make things a bit more declarative:
// this to add a layer of abstraction
// and make things a bit more declarative:
function format(mod) {
var obj = require(mod);
function format(path) {
var obj = require(path);
return function(req, res){
res.format(obj);
}
@@ -38,4 +40,4 @@ app.get('/users', format('./users'));
if (!module.parent) {
app.listen(3000);
console.log('listening on port 3000');
}
}

View File

@@ -1,5 +1,5 @@
!!! 5
doctype html
html
include header
body
block content
block content

View File

@@ -18,7 +18,7 @@ app.resource = function(path, obj) {
obj.range(req, res, a, b, format);
});
this.get(path + '/:id', obj.show);
this.del(path + '/:id', obj.destroy);
this.delete(path + '/:id', obj.destroy);
};
// Fake records

View File

@@ -29,7 +29,7 @@ var users = {
res.send('user ' + req.params.uid);
},
del: function(req, res){
delete: function(req, res){
res.send('delete users');
}
};
@@ -39,7 +39,7 @@ var pets = {
res.send('user ' + req.params.uid + '\'s pets');
},
del: function(req, res){
delete: function(req, res){
res.send('delete ' + req.params.uid + '\'s pet ' + req.params.pid);
}
};
@@ -47,13 +47,13 @@ var pets = {
app.map({
'/users': {
get: users.list,
del: users.del,
delete: users.delete,
'/:uid': {
get: users.get,
'/pets': {
get: pets.list,
'/:pid': {
del: pets.del
delete: pets.delete
}
}
}

View File

@@ -77,7 +77,7 @@ app.get('/user/:id/edit', loadUser, andRestrictToSelf, function(req, res){
res.send('Editing user ' + req.user.name);
});
app.del('/user/:id', loadUser, andRestrictTo('admin'), function(req, res){
app.delete('/user/:id', loadUser, andRestrictTo('admin'), function(req, res){
res.send('Deleted user ' + req.user.name);
});

View File

@@ -23,7 +23,7 @@ main.get('/', function(req, res){
});
main.get('/:sub', function(req, res){
res.send('requsted ' + req.params.sub);
res.send('requested ' + req.params.sub);
});
// Redirect app

View File

@@ -1,4 +1,4 @@
doctype 5
doctype html
html
head
title= title

View File

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

View File

@@ -8,11 +8,11 @@ var connect = require('connect')
, middleware = require('./middleware')
, debug = require('debug')('express:application')
, locals = require('./utils').locals
, compileTrust = require('./utils').compileTrust
, View = require('./view')
, utils = connect.utils
, path = require('path')
, http = require('http')
, join = path.join;
, deprecate = require('./utils').deprecate
, http = require('http');
/**
* Application prototype.
@@ -49,6 +49,7 @@ app.defaultConfiguration = function(){
this.enable('etag');
this.set('env', process.env.NODE_ENV || 'development');
this.set('subdomain offset', 2);
this.set('trust proxy', false);
debug('booting in %s mode', this.get('env'));
// implicit middleware
@@ -185,7 +186,7 @@ app.engine = function(ext, fn){
* could automatically load a user's information from the database without
* any additional code,
*
* The callback uses the same signature as middleware, the only differencing
* The callback uses the same signature as middleware, the only difference
* being that the value of the placeholder is passed, in this case the _id_
* of the user. Once the `next()` function is invoked, just like middleware
* it will continue on to execute the route, or subsequent parameter functions.
@@ -244,7 +245,7 @@ app.param = function(name, fn){
* Mounted servers inherit their parent server's settings.
*
* @param {String} setting
* @param {String} val
* @param {*} [val]
* @return {Server} for chaining
* @api public
*/
@@ -254,6 +255,12 @@ app.set = function(setting, val){
return this.settings[setting];
} else {
this.settings[setting] = val;
if (setting === 'trust proxy') {
debug('compile trust proxy %j', val);
this.set('trust proxy fn', compileTrust(val));
}
return this;
}
};
@@ -402,11 +409,6 @@ methods.forEach(function(method){
app[method] = function(path){
if ('get' == method && 1 == arguments.length) return this.set(path);
// deprecated
if (Array.isArray(path)) {
console.trace('passing an array to app.VERB() is deprecated and will be removed in 4.0');
}
// if no router attached yet, attach the router
if (!this._usedRouter) this.use(this.router);
@@ -436,7 +438,7 @@ app.all = function(path){
// del -> delete alias
app.del = app.delete;
app.del = deprecate(app.delete, 'app.del: Use app.delete instead');
/**
* Render the given view `name` name with `options`
@@ -492,7 +494,7 @@ app.render = function(name, options, fn){
});
if (!view.path) {
var err = new Error('Failed to lookup view "' + name + '"');
var err = new Error('Failed to lookup view "' + name + '" in views directory "' + view.root + '"');
err.view = view;
return fn(err);
}

View File

@@ -2,12 +2,14 @@
* Module dependencies.
*/
var merge = require('merge-descriptors');
var connect = require('connect')
, proto = require('./application')
, Route = require('./router/route')
, Router = require('./router')
, req = require('./request')
, res = require('./response')
, deprecate = require('./utils').deprecate
, utils = connect.utils;
/**
@@ -43,27 +45,21 @@ function createApplication() {
* for example `express.logger` etc.
*/
for (var key in connect.middleware) {
Object.defineProperty(
exports
, key
, Object.getOwnPropertyDescriptor(connect.middleware, key));
}
merge(exports, connect.middleware);
/**
* Error on createServer().
* Deprecated createServer().
*/
exports.createServer = function(){
console.warn('Warning: express.createServer() is deprecated, express');
console.warn('applications no longer inherit from http.Server,');
console.warn('please use:');
console.warn('');
console.warn(' var express = require("express");');
console.warn(' var app = express();');
console.warn('');
return createApplication();
};
exports.createServer = deprecate(createApplication,
'createServer() is deprecated\n' +
'express applications no longer inherit from http.Server\n' +
'please use:\n' +
'\n' +
' var express = require("express");\n' +
' var app = express();\n' +
'\n'
);
/**
* Expose the prototypes.

View File

@@ -8,7 +8,8 @@ var http = require('http')
, connect = require('connect')
, fresh = require('fresh')
, parseRange = require('range-parser')
, parse = connect.utils.parseUrl
, parse = require('parseurl')
, proxyaddr = require('proxy-addr')
, mime = connect.mime;
/**
@@ -337,19 +338,26 @@ req.is = function(type){
/**
* Return the protocol string "http" or "https"
* when requested with TLS. When the "trust proxy"
* setting is enabled the "X-Forwarded-Proto" header
* field will be trusted. If you're running behind
* a reverse proxy that supplies https for you this
* may be enabled.
* setting trusts the socket address, the
* "X-Forwarded-Proto" header field will be trusted.
* If you're running behind a reverse proxy that
* supplies https for you this may be enabled.
*
* @return {String}
* @api public
*/
req.__defineGetter__('protocol', function(){
var trustProxy = this.app.get('trust proxy');
if (this.connection.encrypted) return 'https';
if (!trustProxy) return 'http';
var trust = this.app.get('trust proxy fn');
if (!trust(this.connection.remoteAddress)) {
return this.connection.encrypted
? 'https'
: 'http';
}
// Note: X-Forwarded-Proto is normally only ever a
// single value, but this is to be safe.
var proto = this.get('X-Forwarded-Proto') || 'http';
return proto.split(/\s*,\s*/)[0];
});
@@ -368,36 +376,36 @@ req.__defineGetter__('secure', function(){
});
/**
* Return the remote address, or when
* "trust proxy" is `true` return
* the upstream addr.
* Return the remote address from the trusted proxy.
*
* The is the remote address on the socket unless
* "trust proxy" is set.
*
* @return {String}
* @api public
*/
req.__defineGetter__('ip', function(){
return this.ips[0] || this.connection.remoteAddress;
var trust = this.app.get('trust proxy fn');
return proxyaddr(this, trust);
});
/**
* When "trust proxy" is `true`, parse
* the "X-Forwarded-For" ip address list.
* When "trust proxy" is set, trusted proxy addresses + client.
*
* For example if the value were "client, proxy1, proxy2"
* you would receive the array `["client", "proxy1", "proxy2"]`
* where "proxy2" is the furthest down-stream.
* where "proxy2" is the furthest down-stream and "proxy1" and
* "proxy2" were trusted.
*
* @return {Array}
* @api public
*/
req.__defineGetter__('ips', function(){
var trustProxy = this.app.get('trust proxy');
var val = this.get('X-Forwarded-For');
return trustProxy && val
? val.split(/ *, */)
: [];
var trust = this.app.get('trust proxy fn');
var addrs = proxyaddr.all(this, trust);
return addrs.slice(1).reverse();
});
/**
@@ -467,16 +475,33 @@ req.__defineGetter__('path', function(){
/**
* Parse the "Host" header field hostname.
*
* When the "trust proxy" setting trusts the socket
* address, the "X-Forwarded-Host" header field will
* be trusted.
*
* @return {String}
* @api public
*/
req.__defineGetter__('host', function(){
var trustProxy = this.app.get('trust proxy');
var host = trustProxy && this.get('X-Forwarded-Host');
host = host || this.get('Host');
var trust = this.app.get('trust proxy fn');
var host = this.get('X-Forwarded-Host');
if (!host || !trust(this.connection.remoteAddress)) {
host = this.get('Host');
}
if (!host) return;
return host.split(':')[0];
// IPv6 literal support
var offset = host[0] === '['
? host.indexOf(']') + 1
: 0;
var index = host.indexOf(':', offset);
return ~index
? host.substring(0, index)
: host;
});
/**

View File

@@ -9,14 +9,15 @@ var http = require('http')
, sign = require('cookie-signature').sign
, normalizeType = require('./utils').normalizeType
, normalizeTypes = require('./utils').normalizeTypes
, deprecate = require('./utils').deprecate
, etag = require('./utils').etag
, statusCodes = http.STATUS_CODES
, cookie = require('cookie')
, send = require('send')
, mime = connect.mime
, resolve = require('url').resolve
, basename = path.basename
, extname = path.extname
, join = path.join;
, extname = path.extname;
/**
* Response prototype.
@@ -55,7 +56,9 @@ res.status = function(code){
*/
res.links = function(links){
return this.set('Link', Object.keys(links).map(function(rel){
var link = this.get('Link') || '';
if (link) link += ', ';
return this.set('Link', link + Object.keys(links).map(function(rel){
return '<' + links[rel] + '>; rel="' + rel + '"';
}).join(', '));
};
@@ -131,7 +134,7 @@ res.send = function(body){
// ETag support
// TODO: W/ support
if (app.settings.etag && len > 1024 && 'GET' == req.method) {
if (app.settings.etag && len && 'GET' == req.method) {
if (!this.get('ETag')) {
this.set('ETag', etag(body));
}
@@ -175,6 +178,9 @@ res.json = function(obj){
// res.json(body, status) backwards compat
if ('number' == typeof arguments[1]) {
this.statusCode = arguments[1];
return 'number' === typeof obj
? jsonNumDeprecated.call(this, obj)
: jsonDeprecated.call(this, obj);
} else {
this.statusCode = obj;
obj = arguments[1];
@@ -194,6 +200,12 @@ res.json = function(obj){
return this.send(body);
};
var jsonDeprecated = deprecate(res.json,
'res.json(obj, status): Use res.json(status, obj) instead');
var jsonNumDeprecated = deprecate(res.json,
'res.json(num, status): Use res.status(status).json(num) instead');
/**
* Send JSON response with JSONP callback support.
*
@@ -216,6 +228,9 @@ res.jsonp = function(obj){
// res.json(body, status) backwards compat
if ('number' == typeof arguments[1]) {
this.statusCode = arguments[1];
return 'number' === typeof obj
? jsonpNumDeprecated.call(this, obj)
: jsonpDeprecated.call(this, obj);
} else {
this.statusCode = obj;
obj = arguments[1];
@@ -235,17 +250,27 @@ res.jsonp = function(obj){
this.charset = this.charset || 'utf-8';
this.set('Content-Type', 'application/json');
// fixup callback
if (Array.isArray(callback)) {
callback = callback[0];
}
// jsonp
if (callback) {
if (Array.isArray(callback)) callback = callback[0];
if (callback && 'string' === typeof callback) {
this.set('Content-Type', 'text/javascript');
var cb = callback.replace(/[^\[\]\w$.]/g, '');
body = cb + ' && ' + cb + '(' + body + ');';
body = 'typeof ' + cb + ' === \'function\' && ' + cb + '(' + body + ');';
}
return this.send(body);
};
var jsonpDeprecated = deprecate(res.json,
'res.jsonp(obj, status): Use res.jsonp(status, obj) instead');
var jsonpNumDeprecated = deprecate(res.json,
'res.jsonp(num, status): Use res.status(status).jsonp(num) instead');
/**
* Transfer the file at the given `path`.
*
@@ -309,23 +334,23 @@ res.sendfile = function(path, options, fn){
// clean up
cleanup();
if (!self.headerSent) self.removeHeader('Content-Disposition');
if (!self.headersSent) self.removeHeader('Content-Disposition');
// callback available
if (fn) return fn(err);
// list in limbo if there's no callback
if (self.headerSent) return;
if (self.headersSent) return;
// delegate
next(err);
}
// streaming
function stream() {
function stream(stream) {
if (done) return;
cleanup();
if (fn) self.on('finish', fn);
if (fn) stream.on('end', fn);
}
// cleanup
@@ -350,7 +375,7 @@ res.sendfile = function(path, options, fn){
* Optionally providing an alternate attachment `filename`,
* and optional callback `fn(err)`. The callback is invoked
* when the data transfer is complete, or when an error has
* ocurred. Be sure to check `res.headerSent` if you plan to respond.
* ocurred. Be sure to check `res.headersSent` if you plan to respond.
*
* This method uses `res.sendfile()`.
*
@@ -466,7 +491,10 @@ res.format = function(obj){
this.vary("Accept");
if (key) {
this.set('Content-Type', normalizeType(key).value);
var type = normalizeType(key).value;
var charset = mime.charsets.lookup(type);
if (charset) type += '; charset=' + charset;
this.set('Content-Type', type);
obj[key](req, this, next);
} else if (fn) {
fn();
@@ -600,8 +628,7 @@ res.cookie = function(name, val, options){
/**
* 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
* The given `url` can also be "back", which redirects
* to the _Referrer_ or _Referer_ headers or "/".
*
* Examples:
@@ -629,22 +656,19 @@ res.cookie = function(name, val, options){
res.location = function(url){
var app = this.app
, req = this.req;
, req = this.req
, path;
// setup redirect map
var map = { back: req.get('Referrer') || '/' };
// perform redirect
url = map[url] || url;
// "back" is an alias for the referrer
if ('back' == url) url = req.get('Referrer') || '/';
// 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;
path = req.originalUrl.split('?')[0];
path = path + ('/' == path[path.length - 1] ? '' : '/');
url = resolve(path, url);
// relative to mount-point
} else if ('/' != url[0]) {
path = app.path();
@@ -679,8 +703,7 @@ res.location = function(url){
*/
res.redirect = function(url){
var app = this.app
, head = 'HEAD' == this.req.method
var head = 'HEAD' == this.req.method
, status = 302
, body;
@@ -745,7 +768,7 @@ res.vary = function(field){
var vary = this.get('Vary');
// append
// append
if (vary) {
vary = vary.split(/ *, */);
if (!~vary.indexOf(field)) vary.push(field);

View File

@@ -2,11 +2,11 @@
* Module dependencies.
*/
var Route = require('./route')
, utils = require('../utils')
, methods = require('methods')
, debug = require('debug')('express:router')
, parse = require('connect').utils.parseUrl;
var Route = require('./route');
var utils = require('../utils');
var methods = require('methods');
var debug = require('debug')('express:router');
var parseUrl = require('parseurl');
/**
* Expose `Router` constructor.
@@ -104,7 +104,7 @@ Router.prototype._dispatch = function(req, res, next){
req.route = route = self.matchRequest(req, i);
// implied OPTIONS
if (!route && 'OPTIONS' == req.method) return self._options(req, res);
if (!route && 'OPTIONS' == req.method) return self._options(req, res, next);
// no route
if (!route) return next(err);
@@ -181,9 +181,10 @@ Router.prototype._dispatch = function(req, res, next){
* @api private
*/
Router.prototype._options = function(req, res){
var path = parse(req).pathname
Router.prototype._options = function(req, res, next){
var path = parseUrl(req).pathname
, body = this._optionsFor(path).join(',');
if (!body) return next();
res.set('Allow', body).send(body);
};
@@ -221,7 +222,7 @@ Router.prototype._optionsFor = function(path){
Router.prototype.matchRequest = function(req, i, head){
var method = req.method.toLowerCase()
, url = parse(req)
, url = parseUrl(req)
, path = url.pathname
, routes = this.map
, i = i || 0
@@ -283,7 +284,7 @@ Router.prototype.route = function(method, path, callbacks){
if (!path) throw new Error('Router#' + method + '() requires a path');
// ensure all callbacks are functions
callbacks.forEach(function(fn, i){
callbacks.forEach(function(fn){
if ('function' == typeof fn) return;
var type = {}.toString.call(fn);
var msg = '.' + method + '() requires callback functions but got a ' + type;
@@ -302,6 +303,15 @@ Router.prototype.route = function(method, path, callbacks){
return this;
};
Router.prototype.all = function(path) {
var self = this;
var args = [].slice.call(arguments);
methods.forEach(function(method){
self.route.apply(self, [method].concat(args));
});
return this;
};
methods.forEach(function(method){
Router.prototype[method] = function(path){
var args = [method].concat([].slice.call(arguments));

View File

@@ -57,9 +57,15 @@ Route.prototype.match = function(path){
for (var i = 1, len = m.length; i < len; ++i) {
var key = keys[i - 1];
var val = 'string' == typeof m[i]
? decodeURIComponent(m[i])
: m[i];
try {
var val = 'string' == typeof m[i]
? decodeURIComponent(m[i])
: m[i];
} catch(e) {
var err = new Error("Failed to decode param '" + m[i] + "'");
err.status = 400;
throw err;
}
if (key) {
params[key.name] = val;

View File

@@ -4,6 +4,8 @@
*/
var mime = require('connect').mime
, deprecate = require('util').deprecate
, proxyaddr = require('proxy-addr')
, crc32 = require('buffer-crc32');
/**
@@ -12,6 +14,30 @@ var mime = require('connect').mime
var toString = {}.toString;
/**
* Deprecate function, like core `util.deprecate`,
* but with NODE_ENV and color support.
*
* @param {Function} fn
* @param {String} msg
* @return {Function}
* @api private
*/
exports.deprecate = function(fn, msg){
if (process.env.NODE_ENV === 'test') return fn;
// prepend module name
msg = 'express: ' + msg;
if (process.stderr.isTTY) {
// colorize
msg = '\x1b[31;1m' + msg + '\x1b[0m';
}
return deprecate(fn, msg);
};
/**
* Return ETag for `body`.
*
@@ -34,7 +60,7 @@ exports.etag = function(body){
* @api private
*/
exports.locals = function(obj){
exports.locals = function(){
function locals(obj){
for (var key in obj) locals[key] = obj[key];
return obj;
@@ -312,3 +338,32 @@ exports.pathRegexp = function(path, keys, sensitive, strict) {
.replace(/\*/g, '(.*)');
return new RegExp('^' + path + '$', sensitive ? '' : 'i');
}
/**
* Compile "proxy trust" value to function.
*
* @param {Boolean|String|Number|Array|Function} val
* @return {Function}
* @api private
*/
exports.compileTrust = function(val) {
if (typeof val === 'function') return val;
if (val === true) {
// Support plain true/false
return function(){ return true };
}
if (typeof val === 'number') {
// Support trusting hop count
return function(a, i){ return i < val };
}
if (typeof val === 'string') {
// Support comma-separated values
val = val.split(/ *, */);
}
return proxyaddr.compile(val || []);
}

View File

@@ -1,7 +1,7 @@
{
"name": "express",
"description": "Sinatra inspired web development framework",
"version": "3.4.0",
"version": "3.7.0",
"author": "TJ Holowaychuk <tj@vision-media.ca>",
"contributors": [
{
@@ -16,35 +16,23 @@
"name": "Ciaran Jessup",
"email": "ciaranj@gmail.com"
},
{
"name": "Douglas Christopher Wilson",
"email": "doug@somethingdoug.com"
},
{
"name": "Guillermo Rauch",
"email": "rauchg@gmail.com"
},
{
"name": "Jonathan Ong",
"email": "me@jongleberry.com"
},
{
"name": "Roman Shtylman",
"email": "shtylman+expressjs@gmail.com"
}
],
"dependencies": {
"connect": "2.9.0",
"commander": "1.2.0",
"range-parser": "0.0.4",
"mkdirp": "0.3.5",
"cookie": "0.1.0",
"buffer-crc32": "0.2.1",
"fresh": "0.2.0",
"methods": "0.0.1",
"send": "0.1.4",
"cookie-signature": "1.0.1",
"debug": "*"
},
"devDependencies": {
"ejs": "*",
"mocha": "*",
"jade": "0.30.0",
"hjs": "*",
"stylus": "*",
"should": "*",
"connect-redis": "*",
"marked": "*",
"supertest": "0.6.0"
},
"keywords": [
"express",
"framework",
@@ -57,15 +45,46 @@
"api"
],
"repository": "git://github.com/visionmedia/express",
"main": "index",
"license": "MIT",
"dependencies": {
"connect": "2.16.2",
"commander": "1.3.2",
"methods": "1.0.0",
"mkdirp": "0.5.0",
"parseurl": "1.0.1",
"proxy-addr": "1.0.0",
"range-parser": "1.0.0",
"cookie": "0.1.2",
"buffer-crc32": "0.2.1",
"fresh": "0.2.2",
"send": "0.3.0",
"cookie-signature": "1.0.3",
"merge-descriptors": "0.0.2",
"debug": ">= 0.8.0 < 1"
},
"devDependencies": {
"coveralls": "2.10.0",
"ejs": "~0.8.4",
"istanbul": "0.2.10",
"mocha": "~1.18.2",
"should": "~3.3.1",
"jade": "~0.30.0",
"hjs": "~0.0.6",
"stylus": "~0.40.0",
"connect-redis": "~1.4.5",
"marked": "0.2.10",
"supertest": "~0.12.1"
},
"engines": {
"node": ">= 0.8.0"
},
"bin": {
"express": "./bin/express"
},
"scripts": {
"prepublish": "npm prune",
"test": "make test"
},
"engines": {
"node": "*"
"test": "mocha --require test/support/env --reporter dot --check-leaks test/ test/acceptance/",
"test-cov": "istanbul cover node_modules/mocha/bin/_mocha -- --require test/support/env --reporter dot --check-leaks test/ test/acceptance/",
"test-travis": "istanbul cover node_modules/mocha/bin/_mocha --report lcovonly -- --require test/support/env --reporter spec --check-leaks test/ test/acceptance/ && cat ./coverage/lcov.info | coveralls"
}
}

View File

@@ -1,32 +0,0 @@
#!/usr/bin/env bash
NODE_ENV=production node ./support/app &
pid=$!
bench() {
ab -n 5000 -c 50 -k -q http://127.0.0.1:8000$1 \
| grep "Requests per" \
| cut -d ' ' -f 7 \
| xargs echo "$2:"
}
bench_conditional() {
ab -n 5000 -c 50 -H "If-None-Match: $3" -k -q http://127.0.0.1:8000$1 \
| grep "Requests per" \
| cut -d ' ' -f 7 \
| xargs echo "$2:"
}
sleep .5
bench / "Hello World"
bench /blog "Mounted Hello World"
bench /blog/admin "Mounted 2 Hello World"
bench /middleware "Middleware"
bench /match "Router"
bench /render "Render"
bench /json "JSON tiny"
bench /json/15 "JSON small"
bench /json/50 "JSON medium"
bench /json/150 "JSON large"
kill -9 $pid

View File

@@ -1,7 +1,8 @@
var express = require('../')
, Router = express.Router
, request = require('./support/http')
, request = require('supertest')
, methods = require('methods')
, assert = require('assert');
describe('Router', function(){
@@ -100,4 +101,21 @@ describe('Router', function(){
router.route('get', '/foo', function(){}, function(){});
})
})
describe('.all', function() {
it('should support using .all to capture all http verbs', function() {
var router = new Router();
router.all('/foo', function(){});
var url = '/foo?bar=baz';
methods.forEach(function testMethod(method) {
var route = router.match(method, url);
route.constructor.name.should.equal('Route');
route.method.should.equal(method);
route.path.should.equal('/foo');
});
})
})
})

View File

@@ -1,13 +1,5 @@
var app = require('../../examples/auth/app')
, request = require('../support/http');
function redirects(to, fn){
return function(err, res){
res.statusCode.should.equal(302)
res.headers.should.have.property('location').match(to);
fn()
}
}
var request = require('supertest')
function getCookie(res) {
return res.headers['set-cookie'][0].split(';')[0];
@@ -18,25 +10,93 @@ describe('auth', function(){
it('should redirect to /login', function(done){
request(app)
.get('/')
.end(redirects(/\/login$/, done))
.expect('Location', '/login')
.expect(302, done)
})
})
describe('GET /restricted (w/o cookie)',function(){
it('should redirect to /login', function(done){
describe('GET /login',function(){
it('should render login form', function(done){
request(app)
.get('/restricted')
.end(redirects(/\/login$/,done))
.get('/login')
.expect(200, /<form/, done)
})
})
describe('POST /login', function(){
it('should fail without proper credentials', function(done){
it('should display login error', function(done){
request(app)
.post('/login')
.type('urlencoded')
.send('username=not-tj&password=foobar')
.end(redirects(/\/login$/, done))
.expect('Location', '/login')
.expect(302, function(err, res){
if (err) return done(err)
request(app)
.get('/login')
.set('Cookie', getCookie(res))
.expect(200, /Authentication failed/, done)
})
})
})
})
describe('GET /logout',function(){
it('should redirect to /', function(done){
request(app)
.get('/logout')
.expect('Location', '/')
.expect(302, done)
})
})
describe('GET /restricted',function(){
it('should redirect to /login without cookie', function(done){
request(app)
.get('/restricted')
.expect('Location', '/login')
.expect(302, done)
})
it('should succeed with proper cookie', function(done){
request(app)
.post('/login')
.type('urlencoded')
.send('username=tj&password=foobar')
.expect('Location', '/')
.expect(302, function(err, res){
if (err) return done(err)
request(app)
.get('/restricted')
.set('Cookie', getCookie(res))
.expect(200, done)
})
})
})
describe('POST /login', function(){
it('should fail without proper username', function(done){
request(app)
.post('/login')
.type('urlencoded')
.send('username=not-tj&password=foobar')
.expect('Location', '/login')
.expect(302, done)
})
it('should fail without proper password', function(done){
request(app)
.post('/login')
.type('urlencoded')
.send('username=tj&password=baz')
.expect('Location', '/login')
.expect(302, done)
})
it('should succeed with proper credentials', function(done){
request(app)
.post('/login')
.type('urlencoded')
.send('username=tj&password=foobar')
.expect('Location', '/')
.expect(302, done)
})
})
})

View File

@@ -1,5 +1,5 @@
var request = require('../support/http')
var request = require('supertest')
, app = require('../../examples/content-negotiation');
describe('content-negotiation', function(){

View File

@@ -1,6 +1,6 @@
var app = require('../../examples/cookies/app')
, request = require('../support/http');
, request = require('supertest');
describe('cookies', function(){
describe('GET /', function(){

View File

@@ -1,6 +1,6 @@
var app = require('../../examples/downloads/app')
, request = require('../support/http');
, request = require('supertest');
describe('downloads', function(){
describe('GET /', function(){

View File

@@ -1,5 +1,5 @@
var request = require('../support/http')
var request = require('supertest')
, app = require('../../examples/ejs');
describe('ejs', function(){

View File

@@ -1,6 +1,6 @@
var app = require('../../examples/error-pages')
, request = require('../support/http');
, request = require('supertest');
describe('error-pages', function(){
describe('GET /', function(){

View File

@@ -1,6 +1,6 @@
var app = require('../../examples/error')
, request = require('../support/http');
, request = require('supertest');
describe('error', function(){
describe('GET /', function(){

View File

@@ -1,13 +1,13 @@
var app = require('../../examples/markdown')
, request = require('../support/http');
, request = require('supertest');
describe('markdown', function(){
describe('GET /', function(){
it('should respond with html', function(done){
request(app)
.get('/')
.expect(/<h1>Markdown Example<\/h1>/,done)
.expect(/<h1[^>]*>Markdown Example<\/h1>/,done)
})
})

View File

@@ -1,5 +1,5 @@
var request = require('../support/http')
var request = require('supertest')
, app = require('../../examples/mvc');
describe('mvc', function(){

View File

@@ -1,5 +1,5 @@
var app = require('../../examples/params/app')
, request = require('../support/http');
, request = require('supertest');
describe('params', function(){
describe('GET /', function(){

View File

@@ -1,5 +1,5 @@
var app = require('../../examples/resource/app')
, request = require('../support/http');
, request = require('supertest');
describe('resource', function(){
describe('GET /', function(){

View File

@@ -1,5 +1,5 @@
var request = require('../support/http')
var request = require('supertest')
, app = require('../../examples/web-service');
describe('web-service', function(){

View File

@@ -1,6 +1,6 @@
var express = require('../')
, request = require('./support/http');
, request = require('supertest');
describe('app.all()', function(){
it('should add a router per method', function(done){

View File

@@ -1,6 +1,6 @@
var express = require('../')
, request = require('./support/http');
, request = require('supertest');
describe('app.del()', function(){
it('should alias app.delete()', function(done){

View File

@@ -1,7 +1,7 @@
var express = require('../')
, request = require('./support/http')
, assert = require('assert');
var express = require('../');
var request = require('supertest');
var assert = require('assert');
describe('HEAD', function(){
it('should default to GET', function(done){

View File

@@ -1,6 +1,6 @@
var express = require('../')
, request = require('./support/http');
, request = require('supertest');
describe('app.listen()', function(){
it('should wrap with an HTTP server', function(done){

View File

@@ -1,6 +1,6 @@
var express = require('../')
, request = require('./support/http');
, request = require('supertest');
describe('app', function(){
describe('.locals(obj)', function(){
@@ -14,7 +14,7 @@ describe('app', function(){
app.locals.age.should.equal(2);
})
})
describe('.locals.settings', function(){
it('should expose app settings', function(){
var app = express();

View File

@@ -1,6 +1,6 @@
var express = require('../')
, request = require('./support/http');
, request = require('supertest');
describe('OPTIONS', function(){
it('should default to the routes defined', function(done){
@@ -15,6 +15,30 @@ describe('OPTIONS', function(){
.expect('GET,PUT')
.expect('Allow', 'GET,PUT', done);
})
it('should not respond if the path is not defined', function(done){
var app = express();
app.get('/users', function(req, res){});
request(app)
.options('/other')
.expect(404, done);
})
it('should forward requests down the middleware chain', function(done){
var app = express();
var router = new express.Router();
router.get('/users', function(req, res){});
app.use(router.middleware);
app.get('/other', function(req, res){});
request(app)
.options('/other')
.expect('GET')
.expect('Allow', 'GET', done);
})
})
describe('app.options()', function(){
@@ -34,4 +58,4 @@ describe('app.options()', function(){
.expect('GET')
.expect('Allow', 'GET', done);
})
})
})

View File

@@ -1,6 +1,6 @@
var express = require('../')
, request = require('./support/http');
, request = require('supertest');
describe('app', function(){
describe('.param(fn)', function(){
@@ -52,13 +52,13 @@ describe('app', function(){
app.get('/post/:id', function(req, res){
var id = req.params.id;
id.should.be.a('number');
id.should.be.a.Number;
res.send('' + id);
});
app.get('/user/:uid', function(req, res){
var id = req.params.id;
id.should.be.a('number');
id.should.be.a.Number;
res.send('' + id);
});
@@ -87,7 +87,7 @@ describe('app', function(){
app.get('/user/:id', function(req, res){
var id = req.params.id;
id.should.be.a('number');
id.should.be.a.Number;
res.send('' + id);
});

View File

@@ -59,7 +59,7 @@ describe('app', function(){
var app = express();
app.set('views', __dirname + '/fixtures');
app.render('rawr.jade', function(err){
err.message.should.equal('Failed to lookup view "rawr.jade"');
err.message.should.equal('Failed to lookup view "rawr.jade" in views directory "' + __dirname + '/fixtures"');
done();
});
})

View File

@@ -1,6 +1,6 @@
var express = require('../')
, request = require('./support/http');
, request = require('supertest');
describe('app', function(){
describe('.request', function(){

View File

@@ -1,6 +1,6 @@
var express = require('../')
, request = require('./support/http');
, request = require('supertest');
describe('app', function(){
describe('.response', function(){
@@ -19,7 +19,7 @@ describe('app', function(){
.get('/')
.expect('HEY', done);
})
it('should not be influenced by other app protos', function(done){
var app = express()
, app2 = express();
@@ -27,7 +27,7 @@ describe('app', function(){
app.response.shout = function(str){
this.send(str.toUpperCase());
};
app2.response.shout = function(str){
this.send(str);
};

View File

@@ -1,14 +1,15 @@
var express = require('../')
, request = require('./support/http')
, request = require('supertest')
, assert = require('assert')
, methods = require('methods');
describe('app.router', function(){
describe('methods supported', function(){
methods.forEach(function(method){
methods.concat('del').forEach(function(method){
if (method === 'connect') return;
it('should include ' + method.toUpperCase(), function(done){
if (method == 'delete') method = 'del';
var app = express();
var calls = [];
@@ -27,16 +28,54 @@ describe('app.router', function(){
});
})
it('should decode params', function(done){
var app = express();
describe('decode querystring', function(){
it('should decode correct params', function(done){
var app = express();
app.get('/:name', function(req, res, next){
res.send(req.params.name);
});
app.get('/:name', function(req, res, next){
res.send(req.params.name);
});
request(app)
.get('/foo%2Fbar')
.expect('foo/bar', done);
request(app)
.get('/foo%2Fbar')
.expect('foo/bar', done);
})
it('should not accept params in malformed paths', function(done) {
var app = express();
app.get('/:name', function(req, res, next){
res.send(req.params.name);
});
request(app)
.get('/%foobar')
.expect(400, done);
})
it('should not decode spaces', function(done) {
var app = express();
app.get('/:name', function(req, res, next){
res.send(req.params.name);
});
request(app)
.get('/foo+bar')
.expect('foo+bar', done);
})
it('should work with unicode', function(done) {
var app = express();
app.get('/:name', function(req, res, next){
res.send(req.params.name);
});
request(app)
.get('/%ce%b1')
.expect('\u03b1', done);
})
})
it('should be .use()able', function(done){
@@ -114,8 +153,8 @@ describe('app.router', function(){
var app = express();
app.get(/^\/user\/([0-9]+)\/(view|edit)?$/, function(req, res){
var id = req.params.shift()
, op = req.params.shift();
var id = req.params[0]
, op = req.params[1];
res.end(op + 'ing user ' + id);
});
@@ -290,8 +329,8 @@ describe('app.router', function(){
var app = express();
app.get('/api/*.*', function(req, res){
var resource = req.params.shift()
, format = req.params.shift();
var resource = req.params[0]
, format = req.params[1];
res.end(resource + ' as ' + format);
});

View File

@@ -1,5 +1,5 @@
var express = require('../')
, request = require('./support/http');
, request = require('supertest');
describe('app', function(){
describe('.VERB()', function(){

View File

@@ -1,7 +1,7 @@
var express = require('../')
, assert = require('assert')
, request = require('./support/http');
, request = require('supertest');
describe('app.routes', function(){
it('should be initialized', function(){

View File

@@ -1,6 +1,6 @@
var express = require('../')
, request = require('./support/http');
, request = require('supertest');
describe('app', function(){
it('should emit "mount" when mounted', function(done){
@@ -23,7 +23,7 @@ describe('app', function(){
blog.get('/blog', function(req, res){
res.end('blog');
});
app.use(blog);
request(app)

View File

@@ -1,7 +1,7 @@
var express = require('../')
, request = require('./support/http')
, assert = require('assert');
var express = require('../');
var request = require('supertest');
var assert = require('assert');
describe('exports', function(){
it('should expose connect middleware', function(){
@@ -15,19 +15,19 @@ describe('exports', function(){
})
it('should expose Router', function(){
express.Router.should.be.a('function');
express.Router.should.be.a.Function;
})
it('should expose the application prototype', function(){
express.application.set.should.be.a('function');
express.application.set.should.be.a.Function;
})
it('should expose the request prototype', function(){
express.request.accepts.should.be.a('function');
express.request.accepts.should.be.a.Function;
})
it('should expose the response prototype', function(){
express.response.send.should.be.a('function');
express.response.send.should.be.a.Function;
})
it('should permit modifying the .application prototype', function(){

View File

@@ -1,6 +1,6 @@
//
// var express = require('../')
// , request = require('./support/http');
// , request = require('supertest');
//
// describe('middleware', function(){
// describe('.next()', function(){

View File

@@ -1,6 +1,6 @@
var express = require('../')
, request = require('./support/http');
, request = require('supertest');
describe('throw after .end()', function(){
it('should fail gracefully', function(done){

View File

@@ -1,6 +1,6 @@
var express = require('../')
, request = require('./support/http');
, request = require('supertest');
describe('req', function(){
describe('.accepted', function(){

View File

@@ -1,6 +1,6 @@
var express = require('../')
, request = require('./support/http');
, request = require('supertest');
describe('req', function(){
describe('.acceptedCharsets', function(){

View File

@@ -1,6 +1,6 @@
var express = require('../')
, request = require('./support/http');
, request = require('supertest');
describe('req', function(){
describe('.acceptedEncodings', function(){
@@ -29,6 +29,7 @@ describe('req', function(){
request(app)
.get('/')
.set('Accept-Encoding', '')
.expect(200, done);
})
})

View File

@@ -1,6 +1,6 @@
var express = require('../')
, request = require('./support/http');
, request = require('supertest');
describe('req', function(){
describe('.acceptedLanguages', function(){

View File

@@ -1,6 +1,6 @@
var express = require('../')
, request = require('./support/http');
, request = require('supertest');
describe('req', function(){
describe('.accepts(type)', function(){
@@ -69,7 +69,7 @@ describe('req', function(){
.expect('json', done);
})
describe('.accept(types)', function(){
describe('.accepts(types)', function(){
it('should return the first when Accept is not present', function(done){
var app = express();

View File

@@ -1,6 +1,6 @@
var express = require('../')
, request = require('./support/http');
, request = require('supertest');
describe('req', function(){
describe('.acceptsCharset(type)', function(){

View File

@@ -1,6 +1,6 @@
var express = require('../')
, request = require('./support/http');
, request = require('supertest');
describe('req', function(){
describe('.auth', function(){

View File

@@ -1,6 +1,6 @@
var express = require('../')
, request = require('./support/http');
, request = require('supertest');
describe('req', function(){
describe('.fresh', function(){

View File

@@ -1,6 +1,6 @@
var express = require('../')
, request = require('./support/http')
, request = require('supertest')
, assert = require('assert');
describe('req', function(){

View File

@@ -1,6 +1,6 @@
var express = require('../')
, request = require('./support/http')
, request = require('supertest')
, assert = require('assert');
describe('req', function(){
@@ -18,6 +18,19 @@ describe('req', function(){
.expect('example.com', done);
})
it('should strip port number', function(done){
var app = express();
app.use(function(req, res){
res.end(req.host);
});
request(app)
.post('/')
.set('Host', 'example.com:3000')
.expect('example.com', done);
})
it('should return undefined otherwise', function(done){
var app = express();
@@ -30,5 +43,96 @@ describe('req', function(){
.post('/')
.expect('undefined', done);
})
it('should work with IPv6 Host', function(done){
var app = express();
app.use(function(req, res){
res.end(req.host);
});
request(app)
.post('/')
.set('Host', '[::1]')
.expect('[::1]', done);
})
it('should work with IPv6 Host and port', function(done){
var app = express();
app.use(function(req, res){
res.end(req.host);
});
request(app)
.post('/')
.set('Host', '[::1]:3000')
.expect('[::1]', done);
})
describe('when "trust proxy" is enabled', function(){
it('should respect X-Forwarded-Host', function(done){
var app = express();
app.enable('trust proxy');
app.use(function(req, res){
res.end(req.host);
});
request(app)
.get('/')
.set('Host', 'localhost')
.set('X-Forwarded-Host', 'example.com')
.expect('example.com', done);
})
it('should ignore X-Forwarded-Host if socket addr not trusted', function(done){
var app = express();
app.set('trust proxy', '10.0.0.1');
app.use(function(req, res){
res.end(req.host);
});
request(app)
.get('/')
.set('Host', 'localhost')
.set('X-Forwarded-Host', 'example.com')
.expect('localhost', done);
})
it('should default to Host', function(done){
var app = express();
app.enable('trust proxy');
app.use(function(req, res){
res.end(req.host);
});
request(app)
.get('/')
.set('Host', 'example.com')
.expect('example.com', done);
})
})
describe('when "trust proxy" is disabled', function(){
it('should ignore X-Forwarded-Host', function(done){
var app = express();
app.use(function(req, res){
res.end(req.host);
});
request(app)
.get('/')
.set('Host', 'localhost')
.set('X-Forwarded-Host', 'evil')
.expect('localhost', done);
})
})
})
})

View File

@@ -1,6 +1,6 @@
var express = require('../')
, request = require('./support/http');
, request = require('supertest');
describe('req', function(){
describe('.ip', function(){
@@ -20,6 +20,21 @@ describe('req', function(){
.set('X-Forwarded-For', 'client, p1, p2')
.expect('client', done);
})
it('should return the addr after trusted proxy', function(done){
var app = express();
app.set('trust proxy', 2);
app.use(function(req, res, next){
res.send(req.ip);
});
request(app)
.get('/')
.set('X-Forwarded-For', 'client, p1, p2')
.expect('p1', done);
})
})
describe('when "trust proxy" is disabled', function(){

View File

@@ -1,6 +1,6 @@
var express = require('../')
, request = require('./support/http');
, request = require('supertest');
describe('req', function(){
describe('.ips', function(){
@@ -20,6 +20,21 @@ describe('req', function(){
.set('X-Forwarded-For', 'client, p1, p2')
.expect('["client","p1","p2"]', done);
})
it('should stop at first untrusted', function(done){
var app = express();
app.set('trust proxy', 2);
app.use(function(req, res, next){
res.send(req.ips);
});
request(app)
.get('/')
.set('X-Forwarded-For', 'client, p1, p2')
.expect('["p1","p2"]', done);
})
})
describe('when "trust proxy" is disabled', function(){

View File

@@ -1,6 +1,6 @@
var express = require('../')
, request = require('./support/http');
, request = require('supertest');
function req(ct) {
var req = {

View File

@@ -1,6 +1,6 @@
var express = require('../')
, request = require('./support/http');
, request = require('supertest')
describe('req', function(){
describe('.param(name, default)', function(){
@@ -29,7 +29,7 @@ describe('req', function(){
.get('/?name=tj')
.expect('tj', done);
})
it('should check req.body', function(done){
var app = express();
@@ -44,7 +44,7 @@ describe('req', function(){
.send({ name: 'tj' })
.expect('tj', done);
})
it('should check req.params', function(done){
var app = express();

View File

@@ -1,6 +1,6 @@
var express = require('../')
, request = require('./support/http');
, request = require('supertest');
describe('req', function(){
describe('.path', function(){

View File

@@ -1,6 +1,6 @@
var express = require('../')
, request = require('./support/http');
, request = require('supertest');
describe('req', function(){
describe('.protocol', function(){
@@ -32,6 +32,21 @@ describe('req', function(){
.expect('https', done);
})
it('should ignore X-Forwarded-Proto if socket addr not trusted', function(done){
var app = express();
app.set('trust proxy', '10.0.0.1');
app.use(function(req, res){
res.end(req.protocol);
});
request(app)
.get('/')
.set('X-Forwarded-Proto', 'https')
.expect('http', done);
})
it('should default to http', function(done){
var app = express();

View File

@@ -1,6 +1,6 @@
var express = require('../')
, request = require('./support/http');
, request = require('supertest');
describe('req', function(){
describe('.query', function(){
@@ -18,7 +18,7 @@ describe('req', function(){
done();
});
})
it('should contain the parsed query-string', function(done){
var app = express();

View File

@@ -1,6 +1,6 @@
var express = require('../')
, request = require('./support/http');
, request = require('supertest');
describe('req', function(){
describe('.route', function(){
@@ -12,7 +12,7 @@ describe('req', function(){
req.route.path.should.equal('/user/:id/:op?');
next();
});
app.get('/user/:id/edit', function(req, res){
req.route.method.should.equal('get');
req.route.path.should.equal('/user/:id/edit');

View File

@@ -1,6 +1,6 @@
var express = require('../')
, request = require('./support/http');
, request = require('supertest');
describe('req', function(){
describe('.secure', function(){

View File

@@ -1,59 +1,38 @@
var express = require('../')
, request = require('./support/http');
, request = require('supertest')
describe('req', function(){
describe('.signedCookies', function(){
it('should return a signed JSON cookie', function(done){
var app = express()
, cookieHeader
, val;
/* So we use the same serialization for expected results. */
var replacer = app.get('json replacer')
, spaces = app.get('json spaces');
var app = express();
app.use(express.cookieParser('secret'));
app.use(function(req, res){
res.send(req.signedCookies);
if ('/set' == req.path) {
res.cookie('obj', { foo: 'bar' }, { signed: true });
res.end();
} else {
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' } }, replacer, spaces);
request(app)
.get('/')
.set('Cookie', cookieHeader)
.expect(val, done);
})
.get('/set')
.end(function(err, res){
if (err) return done(err);
var cookie = res.header['set-cookie'];
it('should return a signed cookie', function(done){
var app = express()
, 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){
res.send(req.signedCookies);
request(app)
.get('/')
.set('Cookie', cookie)
.end(function(err, res){
if (err) return don(err);
res.body.should.eql({ obj: { foo: 'bar' } });
done();
});
});
app.response.req = { secret: 'secret' };
app.response.cookie('foo', 'bar', { signed: true });
cookieHeader = app.response.get('set-cookie');
val = JSON.stringify({ foo: 'bar' }, replacer, spaces);
request(app)
.get('/')
.set('Cookie', cookieHeader)
.expect(val, done);
})
})
})

View File

@@ -1,6 +1,6 @@
var express = require('../')
, request = require('./support/http');
, request = require('supertest');
describe('req', function(){
describe('.stale', function(){

View File

@@ -1,6 +1,6 @@
var express = require('../')
, request = require('./support/http');
, request = require('supertest');
describe('req', function(){
describe('.subdomains', function(){
@@ -15,7 +15,7 @@ describe('req', function(){
request(app)
.get('/')
.set('Host', 'tobi.ferrets.example.com')
.expect('["ferrets","tobi"]', done);
.expect(["ferrets","tobi"], done);
})
})
@@ -30,7 +30,7 @@ describe('req', function(){
request(app)
.get('/')
.set('Host', 'example.com')
.expect('[]', done);
.expect([], done);
})
})
@@ -45,7 +45,7 @@ describe('req', function(){
request(app)
.get('/')
.expect('[]', done);
.expect([], done);
})
})
@@ -62,7 +62,7 @@ describe('req', function(){
request(app)
.get('/')
.set('Host', 'tobi.ferrets.sub.example.com')
.expect('["com","example","sub","ferrets","tobi"]', done);
.expect(["com","example","sub","ferrets","tobi"], done);
})
})
@@ -78,7 +78,7 @@ describe('req', function(){
request(app)
.get('/')
.set('Host', 'tobi.ferrets.sub.example.com')
.expect('["ferrets","tobi"]', done);
.expect(["ferrets","tobi"], done);
})
})
@@ -94,7 +94,7 @@ describe('req', function(){
request(app)
.get('/')
.set('Host', 'sub.example.com')
.expect('[]', done);
.expect([], done);
})
})
})

View File

@@ -1,6 +1,6 @@
var express = require('../')
, request = require('./support/http');
, request = require('supertest');
describe('req', function(){
describe('.xhr', function(){
@@ -19,7 +19,7 @@ describe('req', function(){
done();
})
})
it('should case-insensitive', function(done){
var app = express();
@@ -35,7 +35,7 @@ describe('req', function(){
done();
})
})
it('should return false otherwise', function(done){
var app = express();
@@ -51,7 +51,7 @@ describe('req', function(){
done();
})
})
it('should return false when not present', function(done){
var app = express();

View File

@@ -1,6 +1,6 @@
var express = require('../')
, request = require('./support/http');
, request = require('supertest');
describe('res', function(){
describe('.attachment()', function(){
@@ -16,7 +16,7 @@ describe('res', function(){
.expect('Content-Disposition', 'attachment', done);
})
})
describe('.attachment(filename)', function(){
it('should add the filename param', function(done){
var app = express();
@@ -30,7 +30,7 @@ describe('res', function(){
.get('/')
.expect('Content-Disposition', 'attachment; filename="image.png"', done);
})
it('should set the Content-Type', function(done){
var app = express();

View File

@@ -1,6 +1,6 @@
var express = require('../')
, request = require('./support/http');
, request = require('supertest');
describe('res', function(){
describe('.charset', function(){
@@ -17,7 +17,7 @@ describe('res', function(){
.get('/')
.expect("text/x-foo; charset=utf-8", done);
})
it('should take precedence over res.send() defaults', function(done){
var app = express();

View File

@@ -1,6 +1,6 @@
var express = require('../')
, request = require('./support/http');
, request = require('supertest');
describe('res', function(){
describe('.clearCookie(name)', function(){
@@ -20,7 +20,7 @@ describe('res', function(){
})
})
})
describe('.clearCookie(name, options)', function(){
it('should set the given params', function(done){
var app = express();

View File

@@ -1,6 +1,6 @@
var express = require('../')
, request = require('./support/http')
, request = require('supertest')
, utils = require('connect').utils
, cookie = require('cookie');
@@ -39,7 +39,7 @@ describe('res', function(){
done();
})
})
it('should allow multiple calls', function(done){
var app = express();
@@ -58,7 +58,7 @@ describe('res', function(){
})
})
})
describe('.cookie(name, string, options)', function(){
it('should set params', function(done){
var app = express();
@@ -76,7 +76,7 @@ describe('res', function(){
done();
})
})
describe('maxAge', function(){
it('should set relative expires', function(done){
var app = express();

View File

@@ -1,6 +1,6 @@
var express = require('../')
, request = require('./support/http')
, request = require('supertest')
, assert = require('assert');
describe('res', function(){

View File

@@ -1,12 +1,12 @@
var express = require('../')
, request = require('./support/http')
, request = require('supertest')
, utils = require('../lib/utils')
, assert = require('assert');
var app = express();
var app1 = express();
app.use(function(req, res, next){
app1.use(function(req, res, next){
res.format({
'text/plain': function(){
res.send('hey');
@@ -15,7 +15,7 @@ app.use(function(req, res, next){
'text/html': function(){
res.send('<p>hey</p>');
},
'application/json': function(a, b, c){
assert(req == a);
assert(res == b);
@@ -25,7 +25,7 @@ app.use(function(req, res, next){
});
});
app.use(function(err, req, res, next){
app1.use(function(err, req, res, next){
if (!err.types) throw err;
res.send(err.status, 'Supports: ' + err.types.join(', '));
})
@@ -53,10 +53,24 @@ app3.use(function(req, res, next){
})
});
var app4 = express();
app4.get('/', function(req, res, next){
res.format({
text: function(){ res.send('hey') },
html: function(){ res.send('<p>hey</p>') },
json: function(){ res.send({ message: 'hey' }) }
});
});
app4.use(function(err, req, res, next){
res.send(err.status, 'Supports: ' + err.types.join(', '));
})
describe('res', function(){
describe('.format(obj)', function(){
describe('with canonicalized mime types', function(){
test(app);
test(app1);
})
describe('with extnames', function(){
@@ -71,6 +85,10 @@ describe('res', function(){
.expect('default', done);
})
})
describe('in router', function(){
test(app4);
})
})
})
@@ -93,10 +111,27 @@ function test(app) {
request(app)
.get('/')
.set('Accept', 'text/html; q=.5, text/plain')
.expect('Content-Type', 'text/plain')
.expect('Content-Type', 'text/plain; charset=UTF-8')
.expect('hey', done);
})
it('should set the correct charset for the Content-Type', function() {
request(app)
.get('/')
.set('Accept', 'text/html')
.expect('Content-Type', 'text/html; charset=UTF-8');
request(app)
.get('/')
.set('Accept', 'text/plain')
.expect('Content-Type', 'text/plain; charset=UTF-8');
request(app)
.get('/')
.set('Accept', 'application/json')
.expect('Content-Type', 'application/json');
})
it('should Vary: Accept', function(done){
request(app)
.get('/')

View File

@@ -1,6 +1,6 @@
var express = require('../')
, request = require('./support/http')
, request = require('supertest')
, assert = require('assert');
describe('res', function(){
@@ -18,7 +18,7 @@ describe('res', function(){
})
describe('when given primitives', function(){
it('should respond with json', function(done){
it('should respond with json for null', function(done){
var app = express();
app.use(function(req, res){
@@ -33,6 +33,40 @@ describe('res', function(){
done();
})
})
it('should respond with json for Number', function(done){
var app = express();
app.use(function(req, res){
res.json(300);
});
request(app)
.get('/')
.end(function(err, res){
res.statusCode.should.equal(200);
res.headers.should.have.property('content-type', 'application/json; charset=utf-8');
res.text.should.equal('300');
done();
})
})
it('should respond with json for String', function(done){
var app = express();
app.use(function(req, res){
res.json('str');
});
request(app)
.get('/')
.end(function(err, res){
res.statusCode.should.equal(200);
res.headers.should.have.property('content-type', 'application/json; charset=utf-8');
res.text.should.equal('"str"');
done();
})
})
})
describe('when given an array', function(){
@@ -162,6 +196,23 @@ describe('res', function(){
done();
})
})
it('should use status as second number for backwards compat', function(done){
var app = express();
app.use(function(req, res){
res.json(200, 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('200');
done();
})
})
})
it('should not override previous Content-Types', function(done){

View File

@@ -1,6 +1,6 @@
var express = require('../')
, request = require('./support/http')
, request = require('supertest')
, assert = require('assert');
describe('res', function(){
@@ -16,7 +16,7 @@ describe('res', function(){
.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});');
res.text.should.equal('typeof something === \'function\' && something({"count":1});');
done();
})
})
@@ -32,11 +32,27 @@ describe('res', function(){
.get('/?callback=something&callback=somethingelse')
.end(function(err, res){
res.headers.should.have.property('content-type', 'text/javascript; charset=utf-8');
res.text.should.equal('something && something({"count":1});');
res.text.should.equal('typeof something === \'function\' && something({"count":1});');
done();
})
})
it('should ignore object callback parameter with jsonp', function(done){
var app = express();
app.use(function(req, res){
res.jsonp({ count: 1 });
});
request(app)
.get('/?callback[a]=something')
.end(function(err, res){
res.headers.should.have.property('content-type', 'application/json; charset=utf-8');
res.text.should.equal('{"count":1}');
done();
})
})
it('should allow renaming callback', function(done){
var app = express();
@@ -50,10 +66,10 @@ describe('res', function(){
.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});');
res.text.should.equal('typeof something === \'function\' && something({"count":1});');
done();
})
})
})
it('should allow []', function(done){
var app = express();
@@ -66,7 +82,7 @@ describe('res', function(){
.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});');
res.text.should.equal('typeof callbacks[123] === \'function\' && callbacks[123]({"count":1});');
done();
})
})
@@ -82,7 +98,7 @@ describe('res', function(){
.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({});');
res.text.should.equal('typeof foobar === \'function\' && foobar({});');
done();
})
})
@@ -98,7 +114,7 @@ describe('res', function(){
.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"});');
res.text.should.equal('typeof foo === \'function\' && foo({"str":"\\u2028 \\u2029 woot"});');
done();
});
});
@@ -138,7 +154,7 @@ describe('res', function(){
})
})
})
describe('when given an object', function(){
it('should respond with json', function(done){
var app = express();
@@ -157,6 +173,58 @@ describe('res', function(){
})
})
describe('when given primitives', function(){
it('should respond with json for null', 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();
})
})
it('should respond with json for Number', function(done){
var app = express();
app.use(function(req, res){
res.jsonp(300);
});
request(app)
.get('/')
.end(function(err, res){
res.statusCode.should.equal(200);
res.headers.should.have.property('content-type', 'application/json; charset=utf-8');
res.text.should.equal('300');
done();
})
})
it('should respond with json for String', function(done){
var app = express();
app.use(function(req, res){
res.jsonp('str');
});
request(app)
.get('/')
.end(function(err, res){
res.statusCode.should.equal(200);
res.headers.should.have.property('content-type', 'application/json; charset=utf-8');
res.text.should.equal('"str"');
done();
})
})
})
describe('"json replacer" setting', function(){
it('should be passed to JSON.stringify()', function(done){
var app = express();
@@ -211,8 +279,8 @@ describe('res', function(){
})
})
})
describe('.json(status, object)', function(){
describe('.jsonp(status, object)', function(){
it('should respond with json and set the .statusCode', function(done){
var app = express();
@@ -231,7 +299,7 @@ describe('res', function(){
})
})
describe('.json(object, status)', function(){
describe('.jsonp(object, status)', function(){
it('should respond with json and set the .statusCode for backwards compat', function(done){
var app = express();
@@ -248,5 +316,22 @@ describe('res', function(){
done();
})
})
it('should use status as second number for backwards compat', function(done){
var app = express();
app.use(function(req, res){
res.jsonp(200, 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('200');
done();
})
})
})
})

View File

@@ -3,6 +3,11 @@ var express = require('../')
, res = express.response;
describe('res', function(){
beforeEach(function() {
res.removeHeader('link');
});
describe('.links(obj)', function(){
it('should set Link header field', function(){
res.links({
@@ -15,5 +20,22 @@ describe('res', function(){
'<http://api.example.com/users?page=2>; rel="next", '
+ '<http://api.example.com/users?page=5>; rel="last"');
})
it('should set Link header field for multiple calls', function() {
res.links({
next: 'http://api.example.com/users?page=2',
last: 'http://api.example.com/users?page=5'
});
res.links({
prev: 'http://api.example.com/users?page=1',
});
res.get('link')
.should.equal(
'<http://api.example.com/users?page=2>; rel="next", '
+ '<http://api.example.com/users?page=5>; rel="last", '
+ '<http://api.example.com/users?page=1>; rel="prev"');
})
})
})

View File

@@ -1,6 +1,6 @@
var express = require('../')
, request = require('./support/http');
, request = require('supertest');
describe('res', function(){
describe('.locals(obj)', function(){

View File

@@ -1,6 +1,6 @@
var express = require('../')
, request = require('./support/http');
, request = require('supertest');
describe('res', function(){
describe('.location(url)', function(){
@@ -64,7 +64,7 @@ describe('res', function(){
request(app)
.get('/post/1')
.end(function(err, res){
res.headers.should.have.property('location', '/post/1/./edit');
res.headers.should.have.property('location', '/post/1/edit');
done();
})
})
@@ -81,7 +81,24 @@ describe('res', function(){
request(app)
.get('/post/1')
.end(function(err, res){
res.headers.should.have.property('location', '/post/1/../new');
res.headers.should.have.property('location', '/post/new');
done();
})
})
})
describe('with leading ./ and containing ..', function(){
it('should construct path-relative urls', function(done){
var app = express();
app.use(function(req, res){
res.location('./skip/../../new').end();
});
request(app)
.get('/post/1')
.end(function(err, res){
res.headers.should.have.property('location', '/post/new');
done();
})
})

View File

@@ -1,6 +1,6 @@
var express = require('../')
, request = require('./support/http');
, request = require('supertest');
describe('res', function(){
describe('.redirect(url)', function(){
@@ -210,17 +210,17 @@ describe('res', function(){
request(root)
.get('/depth1')
.end(function(err, res){
res.headers.should.have.property('location', '/depth1/./index');
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');
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');
res.headers.should.have.property('location', '/depth1/depth2/depth3/index');
done();
})
})
@@ -231,11 +231,11 @@ describe('res', function(){
request(root)
.get('/depth2')
.end(function(err, res){
res.headers.should.have.property('location', '/depth2/./index');
res.headers.should.have.property('location', '/depth2/index');
request(root)
.get('/depth3')
.end(function(err, res){
res.headers.should.have.property('location', '/depth3/./index');
res.headers.should.have.property('location', '/depth3/index');
done();
})
})

View File

@@ -1,12 +1,12 @@
var express = require('../')
, request = require('./support/http');
, request = require('supertest');
describe('res', function(){
describe('.render(name)', function(){
it('should support absolute paths', function(done){
var app = express();
app.locals.user = { name: 'tobi' };
app.use(function(req, res){
@@ -17,10 +17,10 @@ describe('res', function(){
.get('/')
.expect('<p>tobi</p>', done);
})
it('should support absolute paths with "view engine"', function(done){
var app = express();
app.locals.user = { name: 'tobi' };
app.set('view engine', 'jade');
@@ -35,7 +35,7 @@ describe('res', function(){
it('should expose app.locals', function(done){
var app = express();
app.set('views', __dirname + '/fixtures');
app.locals.user = { name: 'tobi' };
@@ -50,29 +50,29 @@ describe('res', function(){
it('should support index.<engine>', function(done){
var app = express();
app.set('views', __dirname + '/fixtures');
app.set('view engine', 'jade');
app.use(function(req, res){
res.render('blog/post');
});
request(app)
.get('/')
.expect('<h1>blog post</h1>', done);
})
describe('when an error occurs', function(){
it('should next(err)', function(done){
var app = express();
app.set('views', __dirname + '/fixtures');
app.use(function(req, res){
res.render('user.jade');
});
app.use(function(err, req, res, next){
res.end(err.message);
});
@@ -82,11 +82,11 @@ describe('res', function(){
.expect(/user is not defined/, done);
})
})
describe('when "view engine" is given', function(){
it('should render the template', function(done){
var app = express();
app.set('view engine', 'jade');
app.set('views', __dirname + '/fixtures');
@@ -104,9 +104,9 @@ describe('res', function(){
describe('.render(name, option)', function(){
it('should render the template', function(done){
var app = express();
app.set('views', __dirname + '/fixtures');
var user = { name: 'tobi' };
app.use(function(req, res){
@@ -117,10 +117,10 @@ describe('res', function(){
.get('/')
.expect('<p>tobi</p>', done);
})
it('should expose app.locals', function(done){
var app = express();
app.set('views', __dirname + '/fixtures');
app.locals.user = { name: 'tobi' };
@@ -132,10 +132,10 @@ describe('res', function(){
.get('/')
.expect('<p>tobi</p>', done);
})
it('should expose res.locals', function(done){
var app = express();
app.set('views', __dirname + '/fixtures');
app.use(function(req, res){
@@ -147,10 +147,10 @@ describe('res', function(){
.get('/')
.expect('<p>tobi</p>', done);
})
it('should give precedence to res.locals over app.locals', function(done){
var app = express();
app.set('views', __dirname + '/fixtures');
app.locals.user = { name: 'tobi' };
@@ -166,10 +166,10 @@ describe('res', function(){
it('should give precedence to res.render() locals over res.locals', function(done){
var app = express();
app.set('views', __dirname + '/fixtures');
var jane = { name: 'jane' };
app.use(function(req, res){
res.locals.user = { name: 'tobi' };
res.render('user.jade', { user: jane });
@@ -179,14 +179,14 @@ describe('res', function(){
.get('/')
.expect('<p>jane</p>', done);
})
it('should give precedence to res.render() locals over app.locals', function(done){
var app = express();
app.set('views', __dirname + '/fixtures');
app.locals.user = { name: 'tobi' };
var jane = { name: 'jane' };
app.use(function(req, res){
res.render('user.jade', { user: jane });
});

View File

@@ -1,6 +1,6 @@
var express = require('../')
, request = require('./support/http')
, request = require('supertest')
, assert = require('assert');
describe('res', function(){
@@ -321,6 +321,21 @@ describe('res', function(){
describe('"etag" setting', function(){
describe('when enabled', function(){
it('should send ETag even when content-length < 1024', function(done){
var app = express();
app.use(function(req, res){
res.send('kajdslfkasdf');
});
request(app)
.get('/')
.end(function(err, res){
res.headers.should.have.property('etag');
done();
});
})
it('should send ETag ', function(done){
var app = express();

View File

@@ -1,6 +1,6 @@
var express = require('../')
, request = require('./support/http')
, request = require('supertest')
, assert = require('assert');
describe('res', function(){
@@ -42,7 +42,7 @@ describe('res', function(){
app.use(function(req, res){
res.sendfile('test/fixtures/nope.html', function(err){
++calls;
assert(!res.headerSent);
assert(!res.headersSent);
res.send(err.message);
});
});
@@ -51,7 +51,7 @@ describe('res', function(){
.get('/')
.end(function(err, res){
assert(1 == calls, 'called too many times');
res.text.should.equal("ENOENT, stat 'test/fixtures/nope.html'");
res.text.should.startWith("ENOENT, stat");
res.statusCode.should.equal(200);
done();
});
@@ -77,7 +77,7 @@ describe('res', function(){
app.use(function(req, res){
res.sendfile('test/fixtures/foo/../user.html', function(err){
assert(!res.headerSent);
assert(!res.headersSent);
++calls;
res.send(err.message);
});
@@ -95,7 +95,7 @@ describe('res', function(){
app.use(function(req, res){
res.sendfile('test/fixtures/user.html', function(err){
assert(!res.headerSent);
assert(!res.headersSent);
req.socket.listeners('error').should.have.length(1); // node's original handler
done();
});

View File

@@ -1,6 +1,6 @@
var express = require('../')
, request = require('./support/http')
, request = require('supertest')
, res = express.response;
describe('res', function(){
@@ -45,7 +45,7 @@ describe('res', function(){
JSON.stringify(res.get('ETag')).should.equal('["123","456"]');
})
})
describe('.set(object)', function(){
it('should set multiple fields', function(done){
var app = express();

View File

@@ -1,6 +1,6 @@
var express = require('../')
, request = require('./support/http');
, request = require('supertest');
describe('res', function(){
describe('.status(code)', function(){

View File

@@ -1,6 +1,6 @@
var express = require('../')
, request = require('./support/http');
, request = require('supertest');
describe('res', function(){
describe('.type(str)', function(){

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