mirror of
https://github.com/expressjs/express.git
synced 2026-02-26 18:57:43 +00:00
Compare commits
184 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
ff23423d34 | ||
|
|
1d97599f8b | ||
|
|
e465624fd0 | ||
|
|
dc5932d177 | ||
|
|
cfd93b7529 | ||
|
|
8b2208f394 | ||
|
|
00a3b01f39 | ||
|
|
3baca251f0 | ||
|
|
72daae1d92 | ||
|
|
fcbe53ddb5 | ||
|
|
e9851672eb | ||
|
|
9a45f7bd3d | ||
|
|
85834fd146 | ||
|
|
a0c1ac7b45 | ||
|
|
7b0dca0f9c | ||
|
|
34c83d7d29 | ||
|
|
7c6882234e | ||
|
|
2e68ddbae9 | ||
|
|
7724fc6af7 | ||
|
|
2939075f03 | ||
|
|
606f68de02 | ||
|
|
863160ae49 | ||
|
|
edd39fb194 | ||
|
|
a71d264d45 | ||
|
|
8a7a695836 | ||
|
|
de54af4061 | ||
|
|
2f2a652bc9 | ||
|
|
1e638663de | ||
|
|
1684a8792a | ||
|
|
f47c0d9774 | ||
|
|
89e7264e53 | ||
|
|
cada9f61c8 | ||
|
|
373fa55981 | ||
|
|
2bc703cfc2 | ||
|
|
c9865b821d | ||
|
|
9c0de23645 | ||
|
|
b7a38af41d | ||
|
|
661914781e | ||
|
|
6e3f3887e9 | ||
|
|
a66d6bb034 | ||
|
|
2e197e2b98 | ||
|
|
55d1a4f964 | ||
|
|
82a7d7a977 | ||
|
|
dae54b456f | ||
|
|
1b7a044f33 | ||
|
|
18264403b1 | ||
|
|
04d43b7039 | ||
|
|
2dfecfb661 | ||
|
|
250f1f5f6e | ||
|
|
3ac718763f | ||
|
|
05e1555c0d | ||
|
|
855d1e2bf5 | ||
|
|
f0bfb3b2b2 | ||
|
|
4b4db0f7fb | ||
|
|
9bed2b80ee | ||
|
|
bb157c0cbf | ||
|
|
1ef05d4a28 | ||
|
|
0b88208022 | ||
|
|
c9d9ed3493 | ||
|
|
bd8b9f5781 | ||
|
|
9cbcf23df0 | ||
|
|
36e42db05b | ||
|
|
2bf6a1d813 | ||
|
|
e8373d3564 | ||
|
|
e218377a3d | ||
|
|
7d1aed4955 | ||
|
|
b4acbcf1fe | ||
|
|
50cb62c5d2 | ||
|
|
4cf868bd74 | ||
|
|
baa5a7c3e9 | ||
|
|
ee228f7aea | ||
|
|
d5b11c7d1b | ||
|
|
ed7db34bab | ||
|
|
57e45e3af8 | ||
|
|
1dc46478cb | ||
|
|
113ed0927d | ||
|
|
ab8be2d741 | ||
|
|
3b53b11fcd | ||
|
|
9fb661559b | ||
|
|
04882cf72c | ||
|
|
288176bbc9 | ||
|
|
5638a4fc62 | ||
|
|
3b4ce91fa3 | ||
|
|
1c87e5e9a8 | ||
|
|
a887e6a881 | ||
|
|
69290cad6f | ||
|
|
b66c7da05f | ||
|
|
92ddf77453 | ||
|
|
8e2f538983 | ||
|
|
2817d8caf2 | ||
|
|
b7f08fb159 | ||
|
|
0c2768f5bd | ||
|
|
09bede1a92 | ||
|
|
7059d3b71e | ||
|
|
e5de08faa1 | ||
|
|
e43ff076fd | ||
|
|
3ea7381dea | ||
|
|
f1c46f51e5 | ||
|
|
297fb4e0b0 | ||
|
|
9e406dfee2 | ||
|
|
30b7aa8a17 | ||
|
|
c1d16e0016 | ||
|
|
929ffb8d77 | ||
|
|
197a2e3b54 | ||
|
|
6cf6c8b918 | ||
|
|
058d7ec2ea | ||
|
|
752b5f705e | ||
|
|
e7fa579637 | ||
|
|
97781d4112 | ||
|
|
3ddd8e66a7 | ||
|
|
8a1e865e37 | ||
|
|
e850cb3ea3 | ||
|
|
13d3efe8df | ||
|
|
d6ecf785a2 | ||
|
|
19cb39869f | ||
|
|
a38bdf6758 | ||
|
|
bdbdab7fcc | ||
|
|
5aa9670120 | ||
|
|
8ad8cb93cc | ||
|
|
610e172fcf | ||
|
|
6942070a21 | ||
|
|
e283200511 | ||
|
|
54a192a5c5 | ||
|
|
c3bd65eda2 | ||
|
|
7c2ed1d2d6 | ||
|
|
3de81e0147 | ||
|
|
8fe1e2a5b4 | ||
|
|
909dbb81d5 | ||
|
|
26802a689c | ||
|
|
37239fb67f | ||
|
|
018dc40b32 | ||
|
|
52440955e6 | ||
|
|
c2f3d6ce2b | ||
|
|
be858f5d07 | ||
|
|
1f14734f91 | ||
|
|
6d1d694dbb | ||
|
|
ba5c48aa86 | ||
|
|
320d7807a9 | ||
|
|
6650a312b7 | ||
|
|
832c3b3744 | ||
|
|
76691bfd6b | ||
|
|
29fe5ea785 | ||
|
|
7a31a1d311 | ||
|
|
52a820113f | ||
|
|
aec3428489 | ||
|
|
a10f695b6f | ||
|
|
a3c9eacaf1 | ||
|
|
19d685b152 | ||
|
|
8ab44081d4 | ||
|
|
0431d22822 | ||
|
|
138d74aefa | ||
|
|
28562b2cf8 | ||
|
|
e0afda444f | ||
|
|
5a4cac58af | ||
|
|
545dca6c4d | ||
|
|
e59a882389 | ||
|
|
ccd9828535 | ||
|
|
41f0d32355 | ||
|
|
2f19b4fefc | ||
|
|
cd31cecfd1 | ||
|
|
2fe46b3905 | ||
|
|
24974f1f8f | ||
|
|
fd73bd006e | ||
|
|
7388c2c223 | ||
|
|
e2210b0b92 | ||
|
|
30919be2a0 | ||
|
|
10b21b41f7 | ||
|
|
28b8a3b5f7 | ||
|
|
8b2f1bba95 | ||
|
|
c805d80a9b | ||
|
|
d876778d22 | ||
|
|
412e571600 | ||
|
|
3296ed9cb3 | ||
|
|
91835e6816 | ||
|
|
f976625281 | ||
|
|
028d9d8a0c | ||
|
|
8559c0e2a4 | ||
|
|
06ead58240 | ||
|
|
28ca1b5221 | ||
|
|
6d872e6693 | ||
|
|
69453ff889 | ||
|
|
28752cc3c0 | ||
|
|
5fa685b602 | ||
|
|
eb1bbb92c0 |
0
.gitmodules
vendored
0
.gitmodules
vendored
@@ -1,4 +1,4 @@
|
||||
language: node_js
|
||||
node_js:
|
||||
- "0.8"
|
||||
- "0.10"
|
||||
- "0.10"
|
||||
159
History.md
159
History.md
@@ -1,15 +1,156 @@
|
||||
4.0.0 /
|
||||
==================
|
||||
|
||||
3.2.3 / 2013-05-07
|
||||
* remove:
|
||||
- express(1) - moved to [express-generator](https://github.com/expressjs/generator)
|
||||
- `req.accepted*` - use `req.accepts*()` instead
|
||||
- `app.configure` - use logic in your own app code
|
||||
* change:
|
||||
- `req.accepts*` -> `req.accepts*s` - i.e. `req.acceptsEncoding` -> `req.acceptsEncodings`
|
||||
- `req.params` is now an object instead of an array
|
||||
- `json spaces` no longer enabled by default in development
|
||||
* refactor:
|
||||
- `req.accepts*` with [accepts](https://github.com/expressjs/accepts)
|
||||
- `req.is` with [type-is](https://github.com/expressjs/type-is)
|
||||
|
||||
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
|
||||
==================
|
||||
|
||||
* update connect
|
||||
|
||||
3.3.7 / 2013-08-28
|
||||
==================
|
||||
|
||||
* update connect
|
||||
|
||||
3.3.6 / 2013-08-27
|
||||
==================
|
||||
|
||||
* Revert "remove charset from json responses. Closes #1631" (causes issues in some clients)
|
||||
* add: req.accepts take an argument list
|
||||
|
||||
3.3.4 / 2013-07-08
|
||||
==================
|
||||
|
||||
* update send and connect
|
||||
|
||||
3.3.3 / 2013-07-04
|
||||
==================
|
||||
|
||||
* update connect
|
||||
|
||||
3.3.2 / 2013-07-03
|
||||
==================
|
||||
|
||||
* update connect
|
||||
* update send
|
||||
* remove .version export
|
||||
|
||||
3.3.1 / 2013-06-27
|
||||
==================
|
||||
|
||||
* update connect
|
||||
|
||||
3.3.0 / 2013-06-26
|
||||
==================
|
||||
|
||||
* update connect
|
||||
* add support for multiple X-Forwarded-Proto values. Closes #1646
|
||||
* change: remove charset from json responses. Closes #1631
|
||||
* change: return actual booleans from req.accept* functions
|
||||
* fix jsonp callback array throw
|
||||
|
||||
3.2.6 / 2013-06-02
|
||||
==================
|
||||
|
||||
* update connect
|
||||
|
||||
3.2.5 / 2013-05-21
|
||||
==================
|
||||
|
||||
* update connect
|
||||
* update node-cookie
|
||||
* add: throw a meaningful error when there is no default engine
|
||||
* change generation of ETags with res.send() to GET requests only. Closes #1619
|
||||
|
||||
3.2.4 / 2013-05-09
|
||||
==================
|
||||
|
||||
* fix `req.subdomains` when no Host is present
|
||||
* fix `req.host` when no Host is present, return undefined
|
||||
|
||||
3.2.3 / 2013-05-07
|
||||
==================
|
||||
|
||||
* update connect / qs
|
||||
|
||||
3.2.2 / 2013-05-03
|
||||
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
|
||||
@@ -17,27 +158,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.
|
||||
|
||||
|
||||
2
LICENSE
2
LICENSE
@@ -1,6 +1,6 @@
|
||||
(The MIT License)
|
||||
|
||||
Copyright (c) 2009-2011 TJ Holowaychuk <tj@vision-media.ca>
|
||||
Copyright (c) 2009-2013 TJ Holowaychuk <tj@vision-media.ca>
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining
|
||||
a copy of this software and associated documentation files (the
|
||||
|
||||
7
Makefile
7
Makefile
@@ -9,6 +9,7 @@ test: test-unit test-acceptance
|
||||
test-unit:
|
||||
@NODE_ENV=test ./node_modules/.bin/mocha \
|
||||
--reporter $(REPORTER) \
|
||||
--globals setImmediate,clearImmediate \
|
||||
$(MOCHA_OPTS)
|
||||
|
||||
test-acceptance:
|
||||
@@ -23,11 +24,11 @@ test-cov: lib-cov
|
||||
lib-cov:
|
||||
@jscoverage lib lib-cov
|
||||
|
||||
benchmark:
|
||||
@./support/bench
|
||||
bench:
|
||||
@$(MAKE) -C benchmarks
|
||||
|
||||
clean:
|
||||
rm -f coverage.html
|
||||
rm -fr lib-cov
|
||||
|
||||
.PHONY: test test-unit test-acceptance benchmark clean
|
||||
.PHONY: test test-unit test-acceptance bench clean
|
||||
|
||||
88
Readme.md
88
Readme.md
@@ -1,6 +1,8 @@
|
||||

|
||||
[](http://expressjs.com/)
|
||||
|
||||
Fast, unopinionated, minimalist web framework for [node](http://nodejs.org). [](http://travis-ci.org/visionmedia/express) [](https://gemnasium.com/visionmedia/express)
|
||||
Fast, unopinionated, minimalist web framework for [node](http://nodejs.org).
|
||||
|
||||
[](http://travis-ci.org/visionmedia/express) [](https://www.gittip.com/visionmedia/)
|
||||
|
||||
```js
|
||||
var express = require('express');
|
||||
@@ -48,111 +50,55 @@ 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
|
||||
* Visit the [Wiki](http://github.com/visionmedia/express/wiki)
|
||||
* [日本語ドキュメンテーション](http://hideyukisaito.com/doc/expressjs/) by [hideyukisaito](https://github.com/hideyukisaito)
|
||||
* [Русскоязычная документация](http://jsman.ru/express/)
|
||||
* Run express examples [online](https://runnable.com/express)
|
||||
|
||||
## Viewing Examples
|
||||
|
||||
Clone the Express repo, then install the dev dependencies to install all the example / test suite 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
|
||||
|
||||
## 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
13
benchmarks/Makefile
Normal 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
23
benchmarks/middleware.js
Normal 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
16
benchmarks/run
Executable 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
|
||||
25
bin/express
25
bin/express
@@ -4,8 +4,7 @@
|
||||
* Module dependencies.
|
||||
*/
|
||||
|
||||
var exec = require('child_process').exec
|
||||
, program = require('commander')
|
||||
var program = require('commander')
|
||||
, mkdirp = require('mkdirp')
|
||||
, pkg = require('../package.json')
|
||||
, version = pkg.version
|
||||
@@ -16,6 +15,7 @@ var exec = require('child_process').exec
|
||||
|
||||
program
|
||||
.version(version)
|
||||
.usage('[options] [dir]')
|
||||
.option('-s, --sessions', 'add session support')
|
||||
.option('-e, --ejs', 'add ejs engine support (defaults to jade)')
|
||||
.option('-J, --jshtml', 'add jshtml engine support (defaults to jade)')
|
||||
@@ -74,7 +74,7 @@ var users = [
|
||||
*/
|
||||
|
||||
var jadeLayout = [
|
||||
'doctype 5'
|
||||
'doctype html'
|
||||
, 'html'
|
||||
, ' head'
|
||||
, ' title= title'
|
||||
@@ -208,21 +208,22 @@ var app = [
|
||||
, ' * Module dependencies.'
|
||||
, ' */'
|
||||
, ''
|
||||
, 'var express = require(\'express\')'
|
||||
, ' , routes = require(\'./routes\')'
|
||||
, ' , user = require(\'./routes/user\')'
|
||||
, ' , http = require(\'http\')'
|
||||
, ' , path = require(\'path\');'
|
||||
, 'var express = require(\'express\');'
|
||||
, 'var routes = require(\'./routes\');'
|
||||
, 'var user = require(\'./routes/user\');'
|
||||
, 'var http = require(\'http\');'
|
||||
, 'var path = require(\'path\');'
|
||||
, ''
|
||||
, 'var app = express();'
|
||||
, ''
|
||||
, '// 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\')));'
|
||||
@@ -323,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}', '');
|
||||
|
||||
@@ -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'));
|
||||
});
|
||||
});
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
style
|
||||
style.
|
||||
body {
|
||||
padding: 50px;
|
||||
font: 16px "Helvetica Neue", Helvetica;
|
||||
|
||||
@@ -1,8 +1,9 @@
|
||||
|
||||
var express = require('../../')
|
||||
, app = module.exports = express()
|
||||
, users = require('./db');
|
||||
|
||||
// so either you can deal with different types of formatting
|
||||
// for expected response in index.js
|
||||
app.get('/', function(req, res){
|
||||
res.format({
|
||||
html: function(){
|
||||
@@ -24,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');
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
html
|
||||
head
|
||||
title Express
|
||||
script
|
||||
script.
|
||||
// call this whatever you like,
|
||||
// or dump them into individual
|
||||
// props like "var user ="
|
||||
@@ -10,5 +10,5 @@ html
|
||||
h1 Expose client data
|
||||
p The following was exposed to the client:
|
||||
pre
|
||||
script
|
||||
script.
|
||||
document.write(JSON.stringify(data, null, 2))
|
||||
@@ -1,5 +1,5 @@
|
||||
!!! 5
|
||||
doctype html
|
||||
html
|
||||
include header
|
||||
body
|
||||
block content
|
||||
block content
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
|
||||
var express = require('../..')
|
||||
, fs = require('fs')
|
||||
, md = require('github-flavored-markdown').parse;
|
||||
, md = require('marked').parse;
|
||||
|
||||
var app = module.exports = express();
|
||||
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
|
||||
var express = require('../..');
|
||||
|
||||
var app = module.exports = express();
|
||||
@@ -58,10 +57,10 @@ app.use(function(req, res, next){
|
||||
});
|
||||
*/
|
||||
|
||||
next();
|
||||
// empty or "flush" the messages so they
|
||||
// don't build up
|
||||
req.session.messages = [];
|
||||
next();
|
||||
});
|
||||
|
||||
// load controllers
|
||||
@@ -90,4 +89,4 @@ app.use(function(req, res, next){
|
||||
if (!module.parent) {
|
||||
app.listen(3000);
|
||||
console.log('\n listening on port 3000\n');
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
html
|
||||
head
|
||||
title Search example
|
||||
style
|
||||
style.
|
||||
body {
|
||||
font: 14px "Helvetica Neue", Helvetica;
|
||||
padding: 50px;
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
|
||||
/**
|
||||
* Module dependencies.
|
||||
*/
|
||||
@@ -6,14 +5,14 @@
|
||||
var express = require('../..');
|
||||
|
||||
/*
|
||||
edit /etc/vhosts:
|
||||
edit /etc/hosts:
|
||||
|
||||
127.0.0.1 foo.example.com
|
||||
127.0.0.1 bar.example.com
|
||||
127.0.0.1 example.com
|
||||
*/
|
||||
|
||||
// Main app
|
||||
// Main server app
|
||||
|
||||
var main = express();
|
||||
|
||||
@@ -24,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
|
||||
@@ -36,12 +35,12 @@ redirect.all('*', function(req, res){
|
||||
res.redirect('http://example.com:3000/' + req.subdomains[0]);
|
||||
});
|
||||
|
||||
// Main app
|
||||
// Vhost app
|
||||
|
||||
var app = express();
|
||||
|
||||
app.use(express.vhost('*.example.com', redirect))
|
||||
app.use(express.vhost('example.com', main));
|
||||
app.use(express.vhost('*.example.com', redirect)) // Serves all subdomains via Redirect app
|
||||
app.use(express.vhost('example.com', main)); // Serves top level domain via Main server app
|
||||
|
||||
app.listen(3000);
|
||||
console.log('Express app started on port 3000');
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
var express = require('../../')
|
||||
, http = require('http')
|
||||
, GithubView = require('./github-view')
|
||||
, md = require('github-flavored-markdown').parse;
|
||||
, md = require('marked').parse;
|
||||
|
||||
var app = module.exports = express();
|
||||
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
doctype 5
|
||||
doctype html
|
||||
html
|
||||
head
|
||||
title= title
|
||||
style
|
||||
style.
|
||||
body {
|
||||
padding: 50px;
|
||||
font: 16px Helvetica, Arial;
|
||||
|
||||
@@ -10,9 +10,7 @@ var connect = require('connect')
|
||||
, locals = require('./utils').locals
|
||||
, View = require('./view')
|
||||
, utils = connect.utils
|
||||
, path = require('path')
|
||||
, http = require('http')
|
||||
, join = path.join;
|
||||
, http = require('http');
|
||||
|
||||
/**
|
||||
* Application prototype.
|
||||
@@ -46,6 +44,7 @@ app.init = function(){
|
||||
app.defaultConfiguration = function(){
|
||||
// default settings
|
||||
this.enable('x-powered-by');
|
||||
this.enable('etag');
|
||||
this.set('env', process.env.NODE_ENV || 'development');
|
||||
this.set('subdomain offset', 2);
|
||||
debug('booting in %s mode', this.get('env'));
|
||||
@@ -117,7 +116,6 @@ app.use = function(route, fn){
|
||||
fn = function(req, res, next) {
|
||||
var orig = req.app;
|
||||
app.handle(req, res, function(err){
|
||||
req.app = res.app = orig;
|
||||
req.__proto__ = orig.request;
|
||||
res.__proto__ = orig.response;
|
||||
next(err);
|
||||
@@ -185,7 +183,7 @@ app.engine = function(ext, fn){
|
||||
* could automatically load a user's information from the database without
|
||||
* any additional code,
|
||||
*
|
||||
* The callback uses the samesignature as middleware, the only differencing
|
||||
* The callback uses the same signature as middleware, the only difference
|
||||
* being that the value of the placeholder is passed, in this case the _id_
|
||||
* of the user. Once the `next()` function is invoked, just like middleware
|
||||
* it will continue on to execute the route, or subsequent parameter functions.
|
||||
@@ -492,7 +490,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);
|
||||
}
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
* Module dependencies.
|
||||
*/
|
||||
|
||||
var merge = require('merge-descriptors');
|
||||
var connect = require('connect')
|
||||
, proto = require('./application')
|
||||
, Route = require('./router/route')
|
||||
@@ -16,12 +17,6 @@ var connect = require('connect')
|
||||
|
||||
exports = module.exports = createApplication;
|
||||
|
||||
/**
|
||||
* Framework version.
|
||||
*/
|
||||
|
||||
exports.version = '3.2.3';
|
||||
|
||||
/**
|
||||
* Expose mime.
|
||||
*/
|
||||
@@ -38,8 +33,8 @@ exports.mime = connect.mime;
|
||||
function createApplication() {
|
||||
var app = connect();
|
||||
utils.merge(app, proto);
|
||||
app.request = { __proto__: req };
|
||||
app.response = { __proto__: res };
|
||||
app.request = { __proto__: req, app: app };
|
||||
app.response = { __proto__: res, app: app };
|
||||
app.init();
|
||||
return app;
|
||||
}
|
||||
@@ -49,12 +44,7 @@ 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().
|
||||
|
||||
@@ -17,7 +17,6 @@ var utils = require('./utils');
|
||||
|
||||
exports.init = function(app){
|
||||
return function expressInit(req, res, next){
|
||||
req.app = res.app = app;
|
||||
if (app.enabled('x-powered-by')) res.setHeader('X-Powered-By', 'Express');
|
||||
req.res = res;
|
||||
res.req = req;
|
||||
|
||||
@@ -63,6 +63,7 @@ req.header = function(name){
|
||||
* The `type` value may be a single mime type string
|
||||
* such as "application/json", the extension name
|
||||
* such as "json", a comma-delimted list such as "json, html, text/plain",
|
||||
* an argument list such as `"json", "html", "text/plain"`,
|
||||
* or an array `["json", "html", "text/plain"]`. When a list
|
||||
* or array is given the _best_ match, if any is returned.
|
||||
*
|
||||
@@ -89,6 +90,7 @@ req.header = function(name){
|
||||
*
|
||||
* // Accept: text/*;q=.5, application/json
|
||||
* req.accepts(['html', 'json']);
|
||||
* req.accepts('html', 'json');
|
||||
* req.accepts('html, json');
|
||||
* // => "json"
|
||||
*
|
||||
@@ -98,7 +100,8 @@ req.header = function(name){
|
||||
*/
|
||||
|
||||
req.accepts = function(type){
|
||||
return utils.accepts(type, this.get('Accept'));
|
||||
var args = arguments.length > 1 ? [].slice.apply(arguments) : type;
|
||||
return utils.accepts(args, this.get('Accept'));
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -110,7 +113,7 @@ req.accepts = function(type){
|
||||
*/
|
||||
|
||||
req.acceptsEncoding = function(encoding){
|
||||
return ~this.acceptedEncodings.indexOf(encoding);
|
||||
return !! ~this.acceptedEncodings.indexOf(encoding);
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -125,7 +128,7 @@ req.acceptsEncoding = function(encoding){
|
||||
req.acceptsCharset = function(charset){
|
||||
var accepted = this.acceptedCharsets;
|
||||
return accepted.length
|
||||
? ~accepted.indexOf(charset)
|
||||
? !! ~accepted.indexOf(charset)
|
||||
: true;
|
||||
};
|
||||
|
||||
@@ -141,7 +144,7 @@ req.acceptsCharset = function(charset){
|
||||
req.acceptsLanguage = function(lang){
|
||||
var accepted = this.acceptedLanguages;
|
||||
return accepted.length
|
||||
? ~accepted.indexOf(lang)
|
||||
? !! ~accepted.indexOf(lang)
|
||||
: true;
|
||||
};
|
||||
|
||||
@@ -345,11 +348,10 @@ req.is = function(type){
|
||||
|
||||
req.__defineGetter__('protocol', function(){
|
||||
var trustProxy = this.app.get('trust proxy');
|
||||
return this.connection.encrypted
|
||||
? 'https'
|
||||
: trustProxy
|
||||
? (this.get('X-Forwarded-Proto') || 'http')
|
||||
: 'http';
|
||||
if (this.connection.encrypted) return 'https';
|
||||
if (!trustProxy) return 'http';
|
||||
var proto = this.get('X-Forwarded-Proto') || 'http';
|
||||
return proto.split(/\s*,\s*/)[0];
|
||||
});
|
||||
|
||||
/**
|
||||
@@ -445,7 +447,7 @@ req.__defineGetter__('auth', function(){
|
||||
|
||||
req.__defineGetter__('subdomains', function(){
|
||||
var offset = this.app.get('subdomain offset');
|
||||
return this.get('Host')
|
||||
return (this.host || '')
|
||||
.split('.')
|
||||
.reverse()
|
||||
.slice(offset);
|
||||
@@ -473,6 +475,7 @@ req.__defineGetter__('host', function(){
|
||||
var trustProxy = this.app.get('trust proxy');
|
||||
var host = trustProxy && this.get('X-Forwarded-Host');
|
||||
host = host || this.get('Host');
|
||||
if (!host) return;
|
||||
return host.split(':')[0];
|
||||
});
|
||||
|
||||
|
||||
@@ -14,9 +14,9 @@ var http = require('http')
|
||||
, cookie = require('cookie')
|
||||
, send = require('send')
|
||||
, mime = connect.mime
|
||||
, resolve = require('url').resolve
|
||||
, basename = path.basename
|
||||
, extname = path.extname
|
||||
, join = path.join;
|
||||
, extname = path.extname;
|
||||
|
||||
/**
|
||||
* Response prototype.
|
||||
@@ -55,7 +55,9 @@ res.status = function(code){
|
||||
*/
|
||||
|
||||
res.links = function(links){
|
||||
return this.set('Link', Object.keys(links).map(function(rel){
|
||||
var link = this.get('Link') || '';
|
||||
if (link) link += ', ';
|
||||
return this.set('Link', link + Object.keys(links).map(function(rel){
|
||||
return '<' + links[rel] + '>; rel="' + rel + '"';
|
||||
}).join(', '));
|
||||
};
|
||||
@@ -78,9 +80,12 @@ res.links = function(links){
|
||||
*/
|
||||
|
||||
res.send = function(body){
|
||||
var req = this.req
|
||||
, head = 'HEAD' == req.method
|
||||
, len;
|
||||
var req = this.req;
|
||||
var head = 'HEAD' == req.method;
|
||||
var len;
|
||||
|
||||
// settings
|
||||
var app = this.app;
|
||||
|
||||
// allow status / body
|
||||
if (2 == arguments.length) {
|
||||
@@ -128,7 +133,7 @@ res.send = function(body){
|
||||
|
||||
// ETag support
|
||||
// TODO: W/ support
|
||||
if (len > 1024) {
|
||||
if (app.settings.etag && len && 'GET' == req.method) {
|
||||
if (!this.get('ETag')) {
|
||||
this.set('ETag', etag(body));
|
||||
}
|
||||
@@ -234,9 +239,10 @@ res.jsonp = function(obj){
|
||||
|
||||
// jsonp
|
||||
if (callback) {
|
||||
if (Array.isArray(callback)) callback = callback[0];
|
||||
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);
|
||||
@@ -318,10 +324,10 @@ res.sendfile = function(path, options, fn){
|
||||
}
|
||||
|
||||
// streaming
|
||||
function stream() {
|
||||
function stream(stream) {
|
||||
if (done) return;
|
||||
cleanup();
|
||||
if (fn) self.on('finish', fn);
|
||||
if (fn) stream.on('end', fn);
|
||||
}
|
||||
|
||||
// cleanup
|
||||
@@ -459,10 +465,13 @@ res.format = function(obj){
|
||||
|
||||
var key = req.accepts(keys);
|
||||
|
||||
this.set('Vary', 'Accept');
|
||||
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();
|
||||
@@ -596,8 +605,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:
|
||||
@@ -625,22 +633,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();
|
||||
@@ -675,8 +680,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;
|
||||
|
||||
@@ -716,6 +720,44 @@ res.redirect = function(url){
|
||||
this.end(head ? null : body);
|
||||
};
|
||||
|
||||
/**
|
||||
* Add `field` to Vary. If already present in the Vary set, then
|
||||
* this call is simply ignored.
|
||||
*
|
||||
* @param {Array|String} field
|
||||
* @param {ServerResponse} for chaining
|
||||
* @api public
|
||||
*/
|
||||
|
||||
res.vary = function(field){
|
||||
var self = this;
|
||||
|
||||
// nothing
|
||||
if (!field) return this;
|
||||
|
||||
// array
|
||||
if (Array.isArray(field)) {
|
||||
field.forEach(function(field){
|
||||
self.vary(field);
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
var vary = this.get('Vary');
|
||||
|
||||
// append
|
||||
if (vary) {
|
||||
vary = vary.split(/ *, */);
|
||||
if (!~vary.indexOf(field)) vary.push(field);
|
||||
this.set('Vary', vary.join(', '));
|
||||
return this;
|
||||
}
|
||||
|
||||
// set
|
||||
this.set('Vary', field);
|
||||
return this;
|
||||
};
|
||||
|
||||
/**
|
||||
* Render `view` with the given `options` and optional callback `fn`.
|
||||
* When a callback function is given a response will _not_ be made
|
||||
|
||||
@@ -103,6 +103,9 @@ Router.prototype._dispatch = function(req, res, next){
|
||||
// match route
|
||||
req.route = route = self.matchRequest(req, i);
|
||||
|
||||
// implied OPTIONS
|
||||
if (!route && 'OPTIONS' == req.method) return self._options(req, res, next);
|
||||
|
||||
// no route
|
||||
if (!route) return next(err);
|
||||
debug('matched %s %s', route.method, route.path);
|
||||
@@ -170,6 +173,42 @@ Router.prototype._dispatch = function(req, res, next){
|
||||
})(0);
|
||||
};
|
||||
|
||||
/**
|
||||
* Respond to __OPTIONS__ method.
|
||||
*
|
||||
* @param {IncomingMessage} req
|
||||
* @param {ServerResponse} res
|
||||
* @api private
|
||||
*/
|
||||
|
||||
Router.prototype._options = function(req, res, next){
|
||||
var path = parse(req).pathname
|
||||
, body = this._optionsFor(path).join(',');
|
||||
if (!body) return next();
|
||||
res.set('Allow', body).send(body);
|
||||
};
|
||||
|
||||
/**
|
||||
* Return an array of HTTP verbs or "options" for `path`.
|
||||
*
|
||||
* @param {String} path
|
||||
* @return {Array}
|
||||
* @api private
|
||||
*/
|
||||
|
||||
Router.prototype._optionsFor = function(path){
|
||||
var self = this;
|
||||
return methods.filter(function(method){
|
||||
var routes = self.map[method];
|
||||
if (!routes || 'options' == method) return;
|
||||
for (var i = 0, len = routes.length; i < len; ++i) {
|
||||
if (routes[i].match(path)) return true;
|
||||
}
|
||||
}).map(function(method){
|
||||
return method.toUpperCase();
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* Attempt to match a route for `req`
|
||||
* with optional starting index of `i`
|
||||
@@ -245,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;
|
||||
@@ -264,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));
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -34,7 +34,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;
|
||||
@@ -54,6 +54,7 @@ exports.locals = function(obj){
|
||||
exports.isAbsolute = function(path){
|
||||
if ('/' == path[0]) return true;
|
||||
if (':' == path[1] && '\\' == path[2]) return true;
|
||||
if ('\\\\' == path.substring(0, 2)) return true; // Microsoft Azure absolute path
|
||||
};
|
||||
|
||||
/**
|
||||
|
||||
@@ -38,6 +38,7 @@ function View(name, options) {
|
||||
var engines = options.engines;
|
||||
this.defaultEngine = options.defaultEngine;
|
||||
var ext = this.ext = extname(name);
|
||||
if (!ext && !this.defaultEngine) throw new Error('No default engine was specified and no extension was provided.');
|
||||
if (!ext) name += (ext = this.ext = ('.' != this.defaultEngine[0] ? '.' : '') + this.defaultEngine);
|
||||
this.engine = engines[ext] || (engines[ext] = require(ext.slice(1)).__express);
|
||||
this.path = this.lookup(name);
|
||||
|
||||
43
package.json
43
package.json
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"name": "express",
|
||||
"description": "Sinatra inspired web development framework",
|
||||
"version": "3.2.3",
|
||||
"version": "3.4.8",
|
||||
"author": "TJ Holowaychuk <tj@vision-media.ca>",
|
||||
"contributors": [
|
||||
{
|
||||
@@ -22,29 +22,29 @@
|
||||
}
|
||||
],
|
||||
"dependencies": {
|
||||
"connect": "2.7.9",
|
||||
"commander": "0.6.1",
|
||||
"connect": "2.12.0",
|
||||
"commander": "1.3.2",
|
||||
"range-parser": "0.0.4",
|
||||
"mkdirp": "0.3.4",
|
||||
"cookie": "0.0.5",
|
||||
"mkdirp": "0.3.5",
|
||||
"cookie": "0.1.0",
|
||||
"buffer-crc32": "0.2.1",
|
||||
"fresh": "0.1.0",
|
||||
"methods": "0.0.1",
|
||||
"send": "0.1.0",
|
||||
"fresh": "0.2.0",
|
||||
"methods": "0.1.0",
|
||||
"send": "0.1.4",
|
||||
"cookie-signature": "1.0.1",
|
||||
"debug": "*",
|
||||
"qs": "0.6.4"
|
||||
"merge-descriptors": "0.0.1",
|
||||
"debug": ">= 0.7.3 < 1"
|
||||
},
|
||||
"devDependencies": {
|
||||
"ejs": "*",
|
||||
"mocha": "*",
|
||||
"jade": "*",
|
||||
"hjs": "*",
|
||||
"stylus": "*",
|
||||
"should": "*",
|
||||
"connect-redis": "*",
|
||||
"github-flavored-markdown": "*",
|
||||
"supertest": "0.6.0"
|
||||
"ejs": "~0.8.4",
|
||||
"mocha": "~1.15.1",
|
||||
"jade": "~0.30.0",
|
||||
"hjs": "~0.0.6",
|
||||
"stylus": "~0.40.0",
|
||||
"should": "~2.1.1",
|
||||
"connect-redis": "~1.4.5",
|
||||
"marked": "0.2.10",
|
||||
"supertest": "~0.8.1"
|
||||
},
|
||||
"keywords": [
|
||||
"express",
|
||||
@@ -67,6 +67,7 @@
|
||||
"test": "make test"
|
||||
},
|
||||
"engines": {
|
||||
"node": "*"
|
||||
}
|
||||
"node": ">= 0.8.0"
|
||||
},
|
||||
"license": "MIT"
|
||||
}
|
||||
|
||||
@@ -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
|
||||
@@ -2,6 +2,7 @@
|
||||
var express = require('../')
|
||||
, Router = express.Router
|
||||
, request = require('./support/http')
|
||||
, 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');
|
||||
});
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
@@ -7,7 +7,7 @@ describe('markdown', function(){
|
||||
it('should respond with html', function(done){
|
||||
request(app)
|
||||
.get('/')
|
||||
.expect(/<h1>Markdown Example<\/h1>/,done)
|
||||
.expect(/<h1[^>]*>Markdown Example<\/h1>/,done)
|
||||
})
|
||||
})
|
||||
|
||||
|
||||
61
test/app.options.js
Normal file
61
test/app.options.js
Normal file
@@ -0,0 +1,61 @@
|
||||
|
||||
var express = require('../')
|
||||
, request = require('./support/http');
|
||||
|
||||
describe('OPTIONS', function(){
|
||||
it('should default to the routes defined', function(done){
|
||||
var app = express();
|
||||
|
||||
app.del('/', function(){});
|
||||
app.get('/users', function(req, res){});
|
||||
app.put('/users', function(req, res){});
|
||||
|
||||
request(app)
|
||||
.options('/users')
|
||||
.expect('GET,PUT')
|
||||
.expect('Allow', 'GET,PUT', done);
|
||||
})
|
||||
|
||||
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(){
|
||||
it('should override the default behavior', function(done){
|
||||
var app = express();
|
||||
|
||||
app.options('/users', function(req, res){
|
||||
res.set('Allow', 'GET');
|
||||
res.send('GET');
|
||||
});
|
||||
|
||||
app.get('/users', function(req, res){});
|
||||
app.put('/users', function(req, res){});
|
||||
|
||||
request(app)
|
||||
.options('/users')
|
||||
.expect('GET')
|
||||
.expect('Allow', 'GET', done);
|
||||
})
|
||||
})
|
||||
@@ -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);
|
||||
});
|
||||
|
||||
|
||||
@@ -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();
|
||||
});
|
||||
})
|
||||
|
||||
@@ -27,16 +27,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){
|
||||
|
||||
@@ -4,10 +4,6 @@ var express = require('../')
|
||||
, assert = require('assert');
|
||||
|
||||
describe('exports', function(){
|
||||
it('should have .version', function(){
|
||||
express.should.have.property('version');
|
||||
})
|
||||
|
||||
it('should expose connect middleware', function(){
|
||||
express.should.have.property('bodyParser');
|
||||
express.should.have.property('session');
|
||||
@@ -19,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(){
|
||||
@@ -51,7 +47,7 @@ describe('exports', function(){
|
||||
.get('/')
|
||||
.expect('bar', done);
|
||||
})
|
||||
|
||||
|
||||
it('should permit modifying the .response prototype', function(done){
|
||||
express.response.foo = function(){ this.send('bar'); };
|
||||
var app = express();
|
||||
|
||||
@@ -29,6 +29,7 @@ describe('req', function(){
|
||||
|
||||
request(app)
|
||||
.get('/')
|
||||
.set('Accept-Encoding', '')
|
||||
.expect(200, done);
|
||||
})
|
||||
})
|
||||
|
||||
@@ -56,7 +56,20 @@ describe('req', function(){
|
||||
.expect('html', done);
|
||||
})
|
||||
|
||||
describe('.accept(types)', function(){
|
||||
it('should accept an argument list of type names', function(done){
|
||||
var app = express();
|
||||
|
||||
app.use(function(req, res, next){
|
||||
res.end(req.accepts('json', 'html'));
|
||||
});
|
||||
|
||||
request(app)
|
||||
.get('/')
|
||||
.set('Accept', 'application/json')
|
||||
.expect('json', done);
|
||||
})
|
||||
|
||||
describe('.accepts(types)', function(){
|
||||
it('should return the first when Accept is not present', function(done){
|
||||
var app = express();
|
||||
|
||||
|
||||
34
test/req.host.js
Normal file
34
test/req.host.js
Normal file
@@ -0,0 +1,34 @@
|
||||
|
||||
var express = require('../')
|
||||
, request = require('./support/http')
|
||||
, assert = require('assert');
|
||||
|
||||
describe('req', function(){
|
||||
describe('.host', function(){
|
||||
it('should return the Host when present', function(done){
|
||||
var app = express();
|
||||
|
||||
app.use(function(req, res){
|
||||
res.end(req.host);
|
||||
});
|
||||
|
||||
request(app)
|
||||
.post('/')
|
||||
.set('Host', 'example.com')
|
||||
.expect('example.com', done);
|
||||
})
|
||||
|
||||
it('should return undefined otherwise', function(done){
|
||||
var app = express();
|
||||
|
||||
app.use(function(req, res){
|
||||
req.headers.host = null;
|
||||
res.end(String(req.host));
|
||||
});
|
||||
|
||||
request(app)
|
||||
.post('/')
|
||||
.expect('undefined', done);
|
||||
})
|
||||
})
|
||||
})
|
||||
83
test/req.secure.js
Normal file
83
test/req.secure.js
Normal file
@@ -0,0 +1,83 @@
|
||||
|
||||
var express = require('../')
|
||||
, request = require('./support/http');
|
||||
|
||||
describe('req', function(){
|
||||
describe('.secure', function(){
|
||||
describe('when X-Forwarded-Proto is missing', function(){
|
||||
it('should return false when http', function(done){
|
||||
var app = express();
|
||||
|
||||
app.get('/', function(req, res){
|
||||
res.send(req.secure ? 'yes' : 'no');
|
||||
});
|
||||
|
||||
request(app)
|
||||
.get('/')
|
||||
.expect('no', done)
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
describe('.secure', function(){
|
||||
describe('when X-Forwarded-Proto is present', function(){
|
||||
it('should return false when http', function(done){
|
||||
var app = express();
|
||||
|
||||
app.get('/', function(req, res){
|
||||
res.send(req.secure ? 'yes' : 'no');
|
||||
});
|
||||
|
||||
request(app)
|
||||
.get('/')
|
||||
.set('X-Forwarded-Proto', 'https')
|
||||
.expect('no', done)
|
||||
})
|
||||
|
||||
it('should return true when "trust proxy" is enabled', function(done){
|
||||
var app = express();
|
||||
|
||||
app.enable('trust proxy');
|
||||
|
||||
app.get('/', function(req, res){
|
||||
res.send(req.secure ? 'yes' : 'no');
|
||||
});
|
||||
|
||||
request(app)
|
||||
.get('/')
|
||||
.set('X-Forwarded-Proto', 'https')
|
||||
.expect('yes', done)
|
||||
})
|
||||
|
||||
it('should return false when initial proxy is http', function(done){
|
||||
var app = express();
|
||||
|
||||
app.enable('trust proxy');
|
||||
|
||||
app.get('/', function(req, res){
|
||||
res.send(req.secure ? 'yes' : 'no');
|
||||
});
|
||||
|
||||
request(app)
|
||||
.get('/')
|
||||
.set('X-Forwarded-Proto', 'http, https')
|
||||
.expect('no', done)
|
||||
})
|
||||
|
||||
it('should return true when initial proxy is https', function(done){
|
||||
var app = express();
|
||||
|
||||
app.enable('trust proxy');
|
||||
|
||||
app.get('/', function(req, res){
|
||||
res.send(req.secure ? 'yes' : 'no');
|
||||
});
|
||||
|
||||
request(app)
|
||||
.get('/')
|
||||
.set('X-Forwarded-Proto', 'https, http')
|
||||
.expect('yes', done)
|
||||
})
|
||||
})
|
||||
})
|
||||
})
|
||||
@@ -5,55 +5,34 @@ var express = require('../')
|
||||
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);
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
@@ -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,22 @@ describe('req', function(){
|
||||
request(app)
|
||||
.get('/')
|
||||
.set('Host', 'example.com')
|
||||
.expect('[]', done);
|
||||
.expect([], done);
|
||||
})
|
||||
})
|
||||
|
||||
describe('with no host', function(){
|
||||
it('should return an empty array', function(done){
|
||||
var app = express();
|
||||
|
||||
app.use(function(req, res){
|
||||
req.headers.host = null;
|
||||
res.send(req.subdomains);
|
||||
});
|
||||
|
||||
request(app)
|
||||
.get('/')
|
||||
.expect([], done);
|
||||
})
|
||||
})
|
||||
|
||||
@@ -47,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);
|
||||
})
|
||||
})
|
||||
|
||||
@@ -63,7 +78,7 @@ describe('req', function(){
|
||||
request(app)
|
||||
.get('/')
|
||||
.set('Host', 'tobi.ferrets.sub.example.com')
|
||||
.expect('["ferrets","tobi"]', done);
|
||||
.expect(["ferrets","tobi"], done);
|
||||
})
|
||||
})
|
||||
|
||||
@@ -79,7 +94,7 @@ describe('req', function(){
|
||||
request(app)
|
||||
.get('/')
|
||||
.set('Host', 'sub.example.com')
|
||||
.expect('[]', done);
|
||||
.expect([], done);
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
@@ -53,7 +53,7 @@ app3.use(function(req, res, next){
|
||||
})
|
||||
});
|
||||
|
||||
describe('req', function(){
|
||||
describe('res', function(){
|
||||
describe('.format(obj)', function(){
|
||||
describe('with canonicalized mime types', function(){
|
||||
test(app);
|
||||
@@ -79,24 +79,41 @@ function test(app) {
|
||||
request(app)
|
||||
.get('/')
|
||||
.set('Accept', 'text/html; q=.5, application/json, */*; q=.1')
|
||||
.expect('{"message":"hey"}', done);
|
||||
.expect({"message":"hey"}, done);
|
||||
})
|
||||
|
||||
it('should allow wildcard type/subtypes', function(done){
|
||||
request(app)
|
||||
.get('/')
|
||||
.set('Accept', 'text/html; q=.5, application/*, */*; q=.1')
|
||||
.expect('{"message":"hey"}', done);
|
||||
.expect({"message":"hey"}, done);
|
||||
})
|
||||
|
||||
it('should default the Content-Type', function(done){
|
||||
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('/')
|
||||
|
||||
@@ -16,11 +16,27 @@ 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();
|
||||
})
|
||||
})
|
||||
|
||||
it('should use first callback parameter with jsonp', function(done){
|
||||
var app = express();
|
||||
|
||||
app.use(function(req, res){
|
||||
res.jsonp({ count: 1 });
|
||||
});
|
||||
|
||||
request(app)
|
||||
.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('typeof something === \'function\' && something({"count":1});');
|
||||
done();
|
||||
})
|
||||
})
|
||||
|
||||
it('should allow renaming callback', function(done){
|
||||
var app = express();
|
||||
|
||||
@@ -34,10 +50,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();
|
||||
@@ -50,7 +66,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();
|
||||
})
|
||||
})
|
||||
@@ -66,7 +82,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();
|
||||
})
|
||||
})
|
||||
@@ -82,7 +98,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();
|
||||
});
|
||||
});
|
||||
@@ -122,7 +138,7 @@ describe('res', function(){
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
|
||||
describe('when given an object', function(){
|
||||
it('should respond with json', function(done){
|
||||
var app = express();
|
||||
@@ -195,7 +211,7 @@ describe('res', function(){
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
|
||||
describe('.json(status, object)', function(){
|
||||
it('should respond with json and set the .statusCode', function(done){
|
||||
var app = express();
|
||||
|
||||
@@ -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"');
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
@@ -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();
|
||||
})
|
||||
})
|
||||
|
||||
@@ -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();
|
||||
})
|
||||
})
|
||||
|
||||
105
test/res.send.js
105
test/res.send.js
@@ -1,6 +1,7 @@
|
||||
|
||||
var express = require('../')
|
||||
, request = require('./support/http');
|
||||
, request = require('./support/http')
|
||||
, assert = require('assert');
|
||||
|
||||
describe('res', function(){
|
||||
describe('.send(null)', function(){
|
||||
@@ -16,7 +17,7 @@ describe('res', function(){
|
||||
.expect('', done);
|
||||
})
|
||||
})
|
||||
|
||||
|
||||
describe('.send(undefined)', function(){
|
||||
it('should set body to ""', function(done){
|
||||
var app = express();
|
||||
@@ -45,7 +46,7 @@ describe('res', function(){
|
||||
.expect(201, done);
|
||||
})
|
||||
})
|
||||
|
||||
|
||||
describe('.send(code, body)', function(){
|
||||
it('should set .statusCode and body', function(done){
|
||||
var app = express();
|
||||
@@ -107,7 +108,24 @@ describe('res', function(){
|
||||
.expect('ETag', '"-1498647312"')
|
||||
.end(done);
|
||||
})
|
||||
|
||||
|
||||
it('should not set ETag for non-GET/HEAD', function(done){
|
||||
var app = express();
|
||||
|
||||
app.use(function(req, res){
|
||||
var str = Array(1024 * 2).join('-');
|
||||
res.send(str);
|
||||
});
|
||||
|
||||
request(app)
|
||||
.post('/')
|
||||
.end(function(err, res){
|
||||
if (err) return done(err);
|
||||
assert(!res.header.etag, 'has an ETag');
|
||||
done();
|
||||
});
|
||||
})
|
||||
|
||||
it('should not override Content-Type', function(done){
|
||||
var app = express();
|
||||
|
||||
@@ -122,7 +140,7 @@ describe('res', function(){
|
||||
.expect(200, done);
|
||||
})
|
||||
})
|
||||
|
||||
|
||||
describe('.send(Buffer)', function(){
|
||||
it('should send as octet-stream', function(done){
|
||||
var app = express();
|
||||
@@ -172,7 +190,7 @@ describe('res', function(){
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
|
||||
describe('.send(Object)', function(){
|
||||
it('should send as application/json', function(done){
|
||||
var app = express();
|
||||
@@ -224,7 +242,7 @@ describe('res', function(){
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
|
||||
describe('when .statusCode is 304', function(){
|
||||
it('should strip Content-* fields, Transfer-Encoding field, and body', function(done){
|
||||
var app = express();
|
||||
@@ -300,4 +318,77 @@ describe('res', function(){
|
||||
.get('/?callback=foo')
|
||||
.expect('{"foo":"bar"}', done);
|
||||
})
|
||||
|
||||
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();
|
||||
|
||||
app.use(function(req, res){
|
||||
var str = Array(1024 * 2).join('-');
|
||||
res.send(str);
|
||||
});
|
||||
|
||||
request(app)
|
||||
.get('/')
|
||||
.end(function(err, res){
|
||||
res.headers.should.have.property('etag', '"-1498647312"');
|
||||
done();
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('when disabled', function(){
|
||||
it('should send no ETag', function(done){
|
||||
var app = express();
|
||||
|
||||
app.use(function(req, res){
|
||||
var str = Array(1024 * 2).join('-');
|
||||
res.send(str);
|
||||
});
|
||||
|
||||
app.disable('etag');
|
||||
|
||||
request(app)
|
||||
.get('/')
|
||||
.end(function(err, res){
|
||||
res.headers.should.not.have.property('etag');
|
||||
done();
|
||||
});
|
||||
});
|
||||
|
||||
it('should send ETag when manually set', function(done){
|
||||
var app = express();
|
||||
|
||||
app.disable('etag');
|
||||
|
||||
app.use(function(req, res){
|
||||
res.set('etag', 1);
|
||||
res.send(200);
|
||||
});
|
||||
|
||||
request(app)
|
||||
.get('/')
|
||||
.end(function(err, res){
|
||||
res.headers.should.have.property('etag');
|
||||
done();
|
||||
});
|
||||
});
|
||||
});
|
||||
})
|
||||
})
|
||||
|
||||
@@ -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();
|
||||
});
|
||||
|
||||
55
test/res.vary.js
Normal file
55
test/res.vary.js
Normal file
@@ -0,0 +1,55 @@
|
||||
|
||||
var express = require('../')
|
||||
, should = require('should');
|
||||
|
||||
function response() {
|
||||
var res = Object.create(express.response);
|
||||
res._headers = {};
|
||||
return res;
|
||||
}
|
||||
|
||||
describe('res.vary()', function(){
|
||||
describe('with no arguments', function(){
|
||||
it('should not set Vary', function(){
|
||||
var res = response();
|
||||
res.vary();
|
||||
should.not.exist(res.get('Vary'));
|
||||
})
|
||||
})
|
||||
|
||||
describe('with an empty array', function(){
|
||||
it('should not set Vary', function(){
|
||||
var res = response();
|
||||
res.vary([]);
|
||||
should.not.exist(res.get('Vary'));
|
||||
})
|
||||
})
|
||||
|
||||
describe('with an array', function(){
|
||||
it('should set the values', function(){
|
||||
var res = response();
|
||||
res.vary(['Accept', 'Accept-Language', 'Accept-Encoding']);
|
||||
res.get('Vary').should.equal('Accept, Accept-Language, Accept-Encoding');
|
||||
})
|
||||
})
|
||||
|
||||
describe('with a string', function(){
|
||||
it('should set the value', function(){
|
||||
var res = response();
|
||||
res.vary('Accept');
|
||||
res.get('Vary').should.equal('Accept');
|
||||
})
|
||||
})
|
||||
|
||||
describe('when the value is present', function(){
|
||||
it('should not add it again', function(){
|
||||
var res = response();
|
||||
res.vary('Accept');
|
||||
res.vary('Accept-Encoding');
|
||||
res.vary('Accept-Encoding');
|
||||
res.vary('Accept-Encoding');
|
||||
res.vary('Accept');
|
||||
res.get('Vary').should.equal('Accept, Accept-Encoding');
|
||||
})
|
||||
})
|
||||
})
|
||||
Reference in New Issue
Block a user