mirror of
https://github.com/expressjs/express.git
synced 2026-02-27 03:07:33 +00:00
Compare commits
66 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
45f168e873 | ||
|
|
799938683d | ||
|
|
7128f2d11f | ||
|
|
0634bf0b0d | ||
|
|
f9e48c2972 | ||
|
|
909960c0b3 | ||
|
|
8a7876f4d1 | ||
|
|
286c92b13b | ||
|
|
b9872a278f | ||
|
|
1b34fd7efa | ||
|
|
f05c351762 | ||
|
|
8323f19e96 | ||
|
|
565eda9ee5 | ||
|
|
7aea7194d1 | ||
|
|
2f68957c8c | ||
|
|
4ca848e526 | ||
|
|
31a8c7c19c | ||
|
|
f1c435e050 | ||
|
|
fac75a9bff | ||
|
|
4fe03ab223 | ||
|
|
c6122da59b | ||
|
|
131f658779 | ||
|
|
127f77964e | ||
|
|
9f2bd30dc7 | ||
|
|
6e633b31b4 | ||
|
|
1c65643488 | ||
|
|
388ad9067a | ||
|
|
f470f0bdc5 | ||
|
|
72384b0523 | ||
|
|
1b199b7d98 | ||
|
|
09b384ea44 | ||
|
|
56ae55f987 | ||
|
|
1c360a89ba | ||
|
|
8636dee13e | ||
|
|
70e6baf6fc | ||
|
|
3588c1eedc | ||
|
|
8d6f167a81 | ||
|
|
6106188347 | ||
|
|
eeb77541cd | ||
|
|
99b244b47c | ||
|
|
3043672448 | ||
|
|
0477a53c9f | ||
|
|
d9aa7c3bc9 | ||
|
|
986fac583b | ||
|
|
c6d76086e2 | ||
|
|
e2771364eb | ||
|
|
0d5a63798b | ||
|
|
7d15e2bf52 | ||
|
|
31fef407b6 | ||
|
|
6bef3ef891 | ||
|
|
b806846049 | ||
|
|
bc16020976 | ||
|
|
8afb905a43 | ||
|
|
53667728a8 | ||
|
|
5f0a854e29 | ||
|
|
e9ef3dd9cd | ||
|
|
f702884704 | ||
|
|
0cb866845d | ||
|
|
26483029db | ||
|
|
d2adcbdf67 | ||
|
|
d2f963db2a | ||
|
|
fc2bc1362f | ||
|
|
6ae45d0fd3 | ||
|
|
cc185a8c0e | ||
|
|
ae1078944c | ||
|
|
385a05dd10 |
1
.gitignore
vendored
1
.gitignore
vendored
@@ -10,3 +10,4 @@ lib-cov
|
||||
*.swo
|
||||
benchmarks/graphs
|
||||
testing.js
|
||||
node_modules/
|
||||
|
||||
30
.gitmodules
vendored
30
.gitmodules
vendored
@@ -1,30 +0,0 @@
|
||||
[submodule "support/expresso"]
|
||||
path = support/expresso
|
||||
url = git://github.com/visionmedia/expresso.git
|
||||
[submodule "support/haml"]
|
||||
path = support/haml
|
||||
url = git://github.com/visionmedia/haml.js.git
|
||||
[submodule "support/ejs"]
|
||||
path = support/ejs
|
||||
url = git://github.com/visionmedia/ejs.git
|
||||
[submodule "support/connect-form"]
|
||||
path = support/connect-form
|
||||
url = git://github.com/visionmedia/connect-form.git
|
||||
[submodule "support/connect"]
|
||||
path = support/connect
|
||||
url = git://github.com/senchalabs/connect.git
|
||||
[submodule "support/should"]
|
||||
path = support/should
|
||||
url = git://github.com/visionmedia/should.js.git
|
||||
[submodule "support/formidable"]
|
||||
path = support/formidable
|
||||
url = git://github.com/felixge/node-formidable.git
|
||||
[submodule "support/jade"]
|
||||
path = support/jade
|
||||
url = git://github.com/visionmedia/jade.git
|
||||
[submodule "support/qs"]
|
||||
path = support/qs
|
||||
url = git://github.com/visionmedia/node-querystring.git
|
||||
[submodule "support/mime"]
|
||||
path = support/mime
|
||||
url = https://github.com/bentomas/node-mime.git
|
||||
|
||||
31
History.md
31
History.md
@@ -1,4 +1,35 @@
|
||||
|
||||
2.3.6 / 2011-05-20
|
||||
==================
|
||||
|
||||
* Changed; using devDependencies instead of git submodules
|
||||
* Fixed redis session example
|
||||
* Fixed markdown example
|
||||
* Fixed view caching, should not be enabled in development
|
||||
|
||||
2.3.5 / 2011-05-20
|
||||
==================
|
||||
|
||||
* Added export `.view` as alias for `.View`
|
||||
|
||||
2.3.4 / 2011-05-08
|
||||
==================
|
||||
|
||||
* Added `./examples/say`
|
||||
* Fixed `res.sendfile()` bug preventing the transfer of files with spaces
|
||||
|
||||
2.3.3 / 2011-05-03
|
||||
==================
|
||||
|
||||
* Added "case sensitive routes" option.
|
||||
* Changed; split methods supported per rfc [slaskis]
|
||||
* Fixed route-specific middleware when using the same callback function several times
|
||||
|
||||
2.3.2 / 2011-04-27
|
||||
==================
|
||||
|
||||
* Fixed view hints
|
||||
|
||||
2.3.1 / 2011-04-26
|
||||
==================
|
||||
|
||||
|
||||
7
Makefile
7
Makefile
@@ -3,13 +3,8 @@ DOCS = $(shell find docs/*.md)
|
||||
HTMLDOCS =$(DOCS:.md=.html)
|
||||
|
||||
test:
|
||||
@NODE_ENV=test ./support/expresso/bin/expresso \
|
||||
@NODE_ENV=test ./node_modules/.bin/expresso \
|
||||
-I lib \
|
||||
-I support \
|
||||
-I support/connect/lib \
|
||||
-I support/haml/lib \
|
||||
-I support/jade/lib \
|
||||
-I support/ejs/lib \
|
||||
$(TESTFLAGS) \
|
||||
test/*.test.js
|
||||
|
||||
|
||||
24
Readme.md
24
Readme.md
@@ -16,6 +16,10 @@
|
||||
|
||||
$ npm install express
|
||||
|
||||
or to access the `express(1)` executable install globally:
|
||||
|
||||
$ npm install -g express
|
||||
|
||||
## Features
|
||||
|
||||
* Robust routing
|
||||
@@ -72,6 +76,26 @@ Express 1.x is compatible with node 0.2.x and connect < 1.0.
|
||||
|
||||
Express 2.x is compatible with node 0.4.x and connect 1.x
|
||||
|
||||
## Viewing Examples
|
||||
|
||||
First install the dev dependencies to install all the example / test suite deps:
|
||||
|
||||
$ npm install
|
||||
|
||||
then run whichever tests you want:
|
||||
|
||||
$ node examples/jade/app.js
|
||||
|
||||
## Running Tests
|
||||
|
||||
To run the test suite first invoke the following command within the repo, installing the development dependencies:
|
||||
|
||||
$ npm install
|
||||
|
||||
then run the tests:
|
||||
|
||||
$ make test
|
||||
|
||||
## License
|
||||
|
||||
(The MIT License)
|
||||
|
||||
@@ -11,7 +11,7 @@ var fs = require('fs')
|
||||
* Framework version.
|
||||
*/
|
||||
|
||||
var version = '2.3.0';
|
||||
var version = '2.3.6';
|
||||
|
||||
/**
|
||||
* Add session support.
|
||||
|
||||
@@ -1,10 +1,9 @@
|
||||
|
||||
### Development Dependencies
|
||||
|
||||
Express development dependencies are stored within the _./support_ directory. To
|
||||
update them execute:
|
||||
First install the dev dependencies by executing the following command in the repo's directory:
|
||||
|
||||
$ git submodule update --init
|
||||
$ npm install
|
||||
|
||||
### Running Tests
|
||||
|
||||
|
||||
@@ -340,6 +340,8 @@ app.configure('production', function(){
|
||||
<li><em>views</em> Root views directory defaulting to <strong>CWD/views</strong></li>
|
||||
<li><em>view engine</em> Default view engine name for views rendered without extensions</li>
|
||||
<li><em>view options</em> An object specifying global view options</li>
|
||||
<li><em>view cache</em> Enable view caching (enabled in production)</li>
|
||||
<li><em>case sensitive routes</em> Enable case-sensitive routing</li>
|
||||
</ul>
|
||||
|
||||
|
||||
@@ -431,7 +433,7 @@ app.post('/', function(req, res){
|
||||
app.listen(3000);
|
||||
</code></pre>
|
||||
|
||||
<p>Typically we may use a “dumb” placeholder such as “/user/:id” which has no restrictions, however say for example we are limiting a user id to digits, we may use <em>‘/user/:id(\d+)’</em> which will <em>not</em> match unless the placeholder value contains only digits.</p>
|
||||
<p>Typically we may use a “dumb” placeholder such as “/user/:id” which has no restrictions, however say for example we are limiting a user id to digits, we may use <em>‘/user/:id([0-9]+)’</em> which will <em>not</em> match unless the placeholder value contains only digits.</p>
|
||||
|
||||
<h3 id="passing-route control">Passing Route Control</h3>
|
||||
|
||||
@@ -519,6 +521,34 @@ app.use(connect.bodyParser());
|
||||
app.use(express.bodyParser());
|
||||
</code></pre>
|
||||
|
||||
<p>Middleware ordering is important, when Connect receives a request the <em>first</em> middleware we pass to <em>createServer()</em> or <em>use()</em> is executed with three parameters, <em>request</em>, <em>response</em>, and a callback function usually named <em>next</em>. When <em>next()</em> is invoked the second middleware will then have it’s turn and so on. This is important to note because many middleware depend on each other, for example <em>methodOverride()</em> checks <em>req.body.</em>method<em> for the HTTP method override, however </em>bodyParser()<em> parses the request body and populates </em>req.body<em>. Another example of this is cookie parsing and session support, we must first </em>use()<em> </em>cookieParser()<em> followed by </em>session()_.</p>
|
||||
|
||||
<p>Many Express applications may contain the line <em>app.use(app.router)</em>, while this may appear strange, it’s simply the middleware function that contains all defined routes, and performs route lookup based on the current request url and HTTP method. Express allows you to position this middleware, though by default it will be added to the bottom. By positioning the router, we can alter middleware precedence, for example we may want to add error reporting as the <em>last</em> middleware so that any exception passed to <em>next()</em> will be handled by it, or perhaps we want static file serving to have low precedence, allowing our routes to intercept requests to a static file to count downloads etc. This may look a little like below</p>
|
||||
|
||||
<pre><code>app.use(express.logger(...));
|
||||
app.use(express.bodyParser(...));
|
||||
app.use(express.cookieParser(...));
|
||||
app.use(express.session(...));
|
||||
app.use(app.router);
|
||||
app.use(express.static(...));
|
||||
app.use(express.errorHandler(...));
|
||||
</code></pre>
|
||||
|
||||
<p>First we add <em>logger()</em> so that it may wrap node’s <em>req.end()</em> method, providing us with response-time data. Next the request’s body will be parsed (if any), followed by cookie parsing and session support, meaning <em>req.session</em> will be defined by the time we hit our routes in <em>app.router</em>. If a request such as <em>GET /javascripts/jquery.js</em> is handled by our routes, and we do not call <em>next()</em> then the <em>static()</em> middleware will never see this request, however if were to define a route as shown below, we can record stats, refuse downloads, consume download credits etc.</p>
|
||||
|
||||
<pre><code>var downloads = {};
|
||||
|
||||
app.use(app.router);
|
||||
app.use(express.static(__dirname + '/public'));
|
||||
|
||||
app.get('/*', function(req, res, next){
|
||||
var file = req.params[0];
|
||||
downloads[file] = downloads[file] || 0;
|
||||
downloads[file]++;
|
||||
next();
|
||||
});
|
||||
</code></pre>
|
||||
|
||||
<h3 id="route-middleware">Route Middleware</h3>
|
||||
|
||||
<p>Routes may utilize route-specific middleware by passing one or more additional callbacks (or arrays) to the method. This feature is extremely useful for restricting access, loading data used by the route etc.</p>
|
||||
@@ -595,6 +625,8 @@ app.get('/', all, function(){});
|
||||
|
||||
<p>For this example in full, view the <a href="http://github.com/visionmedia/express/blob/master/examples/route-middleware/app.js">route middleware example</a> in the repository.</p>
|
||||
|
||||
<p>There are times when we may want to “skip” passed remaining route middleware, but continue matching subsequent routes. To do this we invoke <code>next()</code> with the string “route” <code>next('route')</code>. If no remaining routes match the request url then Express will respond with 404 Not Found.</p>
|
||||
|
||||
<h3 id="http-methods">HTTP Methods</h3>
|
||||
|
||||
<p>We have seen <em>app.get()</em> a few times, however Express also exposes other familiar HTTP verbs in the same manor, such as <em>app.post()</em>, <em>app.del()</em>, etc.</p>
|
||||
@@ -1155,7 +1187,7 @@ an error occurs, or when the transfer is complete. By default failures call <cod
|
||||
});
|
||||
</code></pre>
|
||||
|
||||
<h3 id="res.download()">res.download(file[, filename[, callback]])</h3>
|
||||
<h3 id="res.download()">res.download(file[, filename[, callback[, callback2]]])</h3>
|
||||
|
||||
<p>Transfer the given <em>file</em> as an attachment with optional alternative <em>filename</em>.</p>
|
||||
|
||||
@@ -1169,13 +1201,22 @@ res.download('path/to/image.png', 'foo.png');
|
||||
res.sendfile(file);
|
||||
</code></pre>
|
||||
|
||||
<p>An optional callback may be supplied as either the second or third argument, which is passed to <em>res.sendfile()</em>:</p>
|
||||
<p>An optional callback may be supplied as either the second or third argument, which is passed to <em>res.sendfile()</em>. Within this callback you may still respond, as the header has not been sent.</p>
|
||||
|
||||
<pre><code>res.download(path, 'expenses.doc', function(err){
|
||||
// handle
|
||||
});
|
||||
</code></pre>
|
||||
|
||||
<p>An optional second callback, <em>callback2</em> may be given to allow you to act on connection related errors, however you should not attempt to respond.</p>
|
||||
|
||||
<pre><code>res.download(path, function(err){
|
||||
// error or finished
|
||||
}, function(err){
|
||||
// connection related error
|
||||
});
|
||||
</code></pre>
|
||||
|
||||
<h3 id="res.send()">res.send(body|status[, headers|status[, status]])</h3>
|
||||
|
||||
<p>The <em>res.send()</em> method is a high level response utility allowing you to pass
|
||||
@@ -1233,7 +1274,7 @@ app.get('/', function(req, res){
|
||||
});
|
||||
</code></pre>
|
||||
|
||||
<h3 id="res.clearcookie()">res.clearCookie(name)</h3>
|
||||
<h3 id="res.clearcookie()">res.clearCookie(name[, options])</h3>
|
||||
|
||||
<p>Clear cookie <em>name</em> by setting “expires” far in the past.</p>
|
||||
|
||||
@@ -1525,9 +1566,7 @@ as well as the <em>name()</em> function exposed.</p>
|
||||
|
||||
<pre><code>- `settings` the app's settings object
|
||||
- `filename` the view's filename
|
||||
- `request` the request object
|
||||
- `response` the response object
|
||||
- `app` the application itself
|
||||
- `layout(path)` specify the layout from within a view
|
||||
</code></pre>
|
||||
|
||||
<p>This method is aliased as <em>app.locals()</em>.</p>
|
||||
|
||||
@@ -83,6 +83,7 @@ Express supports the following settings out of the box:
|
||||
* _view engine_ Default view engine name for views rendered without extensions
|
||||
* _view options_ An object specifying global view options
|
||||
* _view cache_ Enable view caching (enabled in production)
|
||||
* _case sensitive routes_ Enable case-sensitive routing
|
||||
|
||||
### Routing
|
||||
|
||||
@@ -166,7 +167,7 @@ For example we can __POST__ some json, and echo the json back using the _bodyPar
|
||||
|
||||
app.listen(3000);
|
||||
|
||||
Typically we may use a "dumb" placeholder such as "/user/:id" which has no restrictions, however say for example we are limiting a user id to digits, we may use _'/user/:id(\\\\d+)'_ which will _not_ match unless the placeholder value contains only digits.
|
||||
Typically we may use a "dumb" placeholder such as "/user/:id" which has no restrictions, however say for example we are limiting a user id to digits, we may use _'/user/:id([0-9]+)'_ which will _not_ match unless the placeholder value contains only digits.
|
||||
|
||||
### Passing Route Control
|
||||
|
||||
@@ -248,6 +249,33 @@ This is somewhat annoying, so express re-exports these middleware properties, ho
|
||||
app.use(express.logger());
|
||||
app.use(express.bodyParser());
|
||||
|
||||
Middleware ordering is important, when Connect receives a request the _first_ middleware we pass to _createServer()_ or _use()_ is executed with three parameters, _request_, _response_, and a callback function usually named _next_. When _next()_ is invoked the second middleware will then have it's turn and so on. This is important to note because many middleware depend on each other, for example _methodOverride()_ checks _req.body._method_ for the HTTP method override, however _bodyParser()_ parses the request body and populates _req.body_. Another example of this is cookie parsing and session support, we must first _use()_ _cookieParser()_ followed by _session()_.
|
||||
|
||||
Many Express applications may contain the line _app.use(app.router)_, while this may appear strange, it's simply the middleware function that contains all defined routes, and performs route lookup based on the current request url and HTTP method. Express allows you to position this middleware, though by default it will be added to the bottom. By positioning the router, we can alter middleware precedence, for example we may want to add error reporting as the _last_ middleware so that any exception passed to _next()_ will be handled by it, or perhaps we want static file serving to have low precedence, allowing our routes to intercept requests to a static file to count downloads etc. This may look a little like below
|
||||
|
||||
app.use(express.logger(...));
|
||||
app.use(express.bodyParser(...));
|
||||
app.use(express.cookieParser(...));
|
||||
app.use(express.session(...));
|
||||
app.use(app.router);
|
||||
app.use(express.static(...));
|
||||
app.use(express.errorHandler(...));
|
||||
|
||||
First we add _logger()_ so that it may wrap node's _req.end()_ method, providing us with response-time data. Next the request's body will be parsed (if any), followed by cookie parsing and session support, meaning _req.session_ will be defined by the time we hit our routes in _app.router_. If a request such as _GET /javascripts/jquery.js_ is handled by our routes, and we do not call _next()_ then the _static()_ middleware will never see this request, however if were to define a route as shown below, we can record stats, refuse downloads, consume download credits etc.
|
||||
|
||||
var downloads = {};
|
||||
|
||||
app.use(app.router);
|
||||
app.use(express.static(__dirname + '/public'));
|
||||
|
||||
app.get('/*', function(req, res, next){
|
||||
var file = req.params[0];
|
||||
downloads[file] = downloads[file] || 0;
|
||||
downloads[file]++;
|
||||
next();
|
||||
});
|
||||
|
||||
|
||||
### Route Middleware
|
||||
|
||||
Routes may utilize route-specific middleware by passing one or more additional callbacks (or arrays) to the method. This feature is extremely useful for restricting access, loading data used by the route etc.
|
||||
@@ -319,6 +347,8 @@ Commonly used "stacks" of middleware can be passed as an array (_applied recursi
|
||||
|
||||
For this example in full, view the [route middleware example](http://github.com/visionmedia/express/blob/master/examples/route-middleware/app.js) in the repository.
|
||||
|
||||
There are times when we may want to "skip" passed remaining route middleware, but continue matching subsequent routes. To do this we invoke `next()` with the string "route" `next('route')`. If no remaining routes match the request url then Express will respond with 404 Not Found.
|
||||
|
||||
### HTTP Methods
|
||||
|
||||
We have seen _app.get()_ a few times, however Express also exposes other familiar HTTP verbs in the same manor, such as _app.post()_, _app.del()_, etc.
|
||||
|
||||
@@ -1,7 +1,4 @@
|
||||
|
||||
// Expose modules in ./support for demo purposes
|
||||
require.paths.unshift(__dirname + '/../../support');
|
||||
|
||||
/**
|
||||
* Module dependencies.
|
||||
*/
|
||||
|
||||
@@ -1,7 +1,4 @@
|
||||
|
||||
// Expose modules in ./support for demo purposes
|
||||
require.paths.unshift(__dirname + '/../../support');
|
||||
|
||||
/**
|
||||
* Module dependencies.
|
||||
*/
|
||||
|
||||
@@ -1,7 +1,4 @@
|
||||
|
||||
// Expose modules in ./support for demo purposes
|
||||
require.paths.unshift(__dirname + '/../../support');
|
||||
|
||||
/**
|
||||
* Module dependencies.
|
||||
*/
|
||||
|
||||
@@ -1,7 +1,4 @@
|
||||
|
||||
// Expose modules in ./support for demo purposes
|
||||
require.paths.unshift(__dirname + '/../../support');
|
||||
|
||||
/**
|
||||
* Module dependencies.
|
||||
*/
|
||||
@@ -24,13 +21,20 @@ app.get('/files/:file(*)', function(req, res, next){
|
||||
, path = __dirname + '/files/' + file;
|
||||
// either res.download(path) and let
|
||||
// express handle failures, or provide
|
||||
// a callback
|
||||
// a callback as shown below
|
||||
res.download(path, function(err){
|
||||
// if an error occurs in this callback
|
||||
// the file most likely does not exist,
|
||||
// and it's safe to respond or next(err)
|
||||
if (err) return next(err);
|
||||
// the response has invoked .end()
|
||||
// so you cannnot respond here (of course)
|
||||
// but the callback is handy for statistics etc.
|
||||
|
||||
// the file has been transferred, do not respond
|
||||
// from here, though you may use this callback
|
||||
// for stats etc.
|
||||
console.log('transferred %s', path);
|
||||
}, function(err){
|
||||
// this second optional callback is used when
|
||||
// an error occurs during transmission
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
@@ -1,7 +1,4 @@
|
||||
|
||||
// Expose modules in ./support for demo purposes
|
||||
require.paths.unshift(__dirname + '/../../support');
|
||||
|
||||
/**
|
||||
* Module dependencies.
|
||||
*/
|
||||
|
||||
@@ -1,7 +1,4 @@
|
||||
|
||||
// Expose modules in ./support for demo purposes
|
||||
require.paths.unshift(__dirname + '/../../support');
|
||||
|
||||
/**
|
||||
* Module dependencies.
|
||||
*/
|
||||
@@ -25,4 +22,5 @@ app.get('/next', function(req, res, next){
|
||||
// text/html, and application/json responses to aid in development
|
||||
app.use('/', express.errorHandler({ dump: true, stack: true }));
|
||||
|
||||
app.listen(3000);
|
||||
app.listen(3000);
|
||||
console.log('app listening on port 3000');
|
||||
@@ -1,7 +1,4 @@
|
||||
|
||||
// Expose modules in ./support for demo purposes
|
||||
require.paths.unshift(__dirname + '/../../support');
|
||||
|
||||
/**
|
||||
* Module dependencies.
|
||||
*/
|
||||
|
||||
@@ -1,7 +1,4 @@
|
||||
|
||||
// Expose modules in ./support for demo purposes
|
||||
require.paths.unshift(__dirname + '/../../support');
|
||||
|
||||
/**
|
||||
* Module dependencies.
|
||||
*/
|
||||
|
||||
@@ -1,7 +1,4 @@
|
||||
|
||||
// Expose modules in ./support for demo purposes
|
||||
require.paths.unshift(__dirname + '/../../support');
|
||||
|
||||
/**
|
||||
* Module dependencies.
|
||||
*/
|
||||
|
||||
@@ -1,7 +1,4 @@
|
||||
|
||||
// Expose modules in ./support for demo purposes
|
||||
require.paths.unshift(__dirname + '/../../support');
|
||||
|
||||
/**
|
||||
* Module dependencies.
|
||||
*/
|
||||
|
||||
@@ -1,7 +1,4 @@
|
||||
|
||||
// Expose modules in ./support for demo purposes
|
||||
require.paths.unshift(__dirname + '/../../support');
|
||||
|
||||
/**
|
||||
* Module dependencies.
|
||||
*/
|
||||
@@ -15,7 +12,7 @@ app.set('views', __dirname + '/views');
|
||||
// set default layout, usually "layout"
|
||||
app.set('view options', { layout: 'layouts/default' });
|
||||
|
||||
// Set our default template engine to "jade"
|
||||
// Set our default template engine to "ejs"
|
||||
// which prevents the need for extensions
|
||||
// (although you can still mix and match)
|
||||
app.set('view engine', 'ejs');
|
||||
|
||||
@@ -1,15 +1,10 @@
|
||||
|
||||
// Expose modules in ./support for demo purposes
|
||||
require.paths.unshift(__dirname + '/../../support');
|
||||
|
||||
// $ npm install markdown
|
||||
|
||||
/**
|
||||
* Module dependencies.
|
||||
*/
|
||||
|
||||
var express = require('../../lib/express')
|
||||
, md = require('markdown').markdown;
|
||||
, md = require('node-markdown').Markdown;
|
||||
|
||||
var app = express.createServer();
|
||||
|
||||
@@ -19,7 +14,7 @@ var app = express.createServer();
|
||||
|
||||
app.register('.md', {
|
||||
compile: function(str, options){
|
||||
var html = md.toHTML(str);
|
||||
var html = md(str);
|
||||
return function(locals){
|
||||
return html.replace(/\{([^}]+)\}/g, function(_, name){
|
||||
return locals[name];
|
||||
|
||||
@@ -1,7 +1,4 @@
|
||||
|
||||
// Expose modules in ./support for demo purposes
|
||||
require.paths.unshift(__dirname + '/../../support');
|
||||
|
||||
/**
|
||||
* Module dependencies.
|
||||
*/
|
||||
|
||||
@@ -1,7 +1,4 @@
|
||||
|
||||
// Expose modules in ./support for demo purposes
|
||||
require.paths.unshift(__dirname + '/../../support');
|
||||
|
||||
/**
|
||||
* Module dependencies.
|
||||
*/
|
||||
|
||||
@@ -1,7 +1,4 @@
|
||||
|
||||
// Expose modules in ./support for demo purposes
|
||||
require.paths.unshift(__dirname + '/../../support');
|
||||
|
||||
/**
|
||||
* Module dependencies.
|
||||
*/
|
||||
|
||||
@@ -1,7 +1,4 @@
|
||||
|
||||
// Expose modules in ./support for demo purposes
|
||||
require.paths.unshift(__dirname + '/../../support');
|
||||
|
||||
/**
|
||||
* Module dependencies.
|
||||
*/
|
||||
|
||||
@@ -1,7 +1,4 @@
|
||||
|
||||
// Expose modules in ./support for demo purposes
|
||||
require.paths.unshift(__dirname + '/../../support');
|
||||
|
||||
/**
|
||||
* Module dependencies.
|
||||
*/
|
||||
|
||||
@@ -1,7 +1,4 @@
|
||||
|
||||
// Expose modules in ./support for demo purposes
|
||||
require.paths.unshift(__dirname + '/../../support');
|
||||
|
||||
/**
|
||||
* Module dependencies.
|
||||
*/
|
||||
|
||||
@@ -1,7 +1,4 @@
|
||||
|
||||
// Expose modules in ./support for demo purposes
|
||||
require.paths.unshift(__dirname + '/../../support');
|
||||
|
||||
/**
|
||||
* Module dependencies.
|
||||
*/
|
||||
|
||||
@@ -1,7 +1,4 @@
|
||||
|
||||
// Expose modules in ./support for demo purposes
|
||||
require.paths.unshift(__dirname + '/../../support');
|
||||
|
||||
/**
|
||||
* Module dependencies.
|
||||
*/
|
||||
|
||||
44
examples/say/app.js
Normal file
44
examples/say/app.js
Normal file
@@ -0,0 +1,44 @@
|
||||
|
||||
/**
|
||||
* Module dependencies.
|
||||
*/
|
||||
|
||||
var express = require('../../')
|
||||
, path = require('path')
|
||||
, exec = require('child_process').exec
|
||||
, fs = require('fs');
|
||||
|
||||
/**
|
||||
* Error handler.
|
||||
*/
|
||||
|
||||
function errorHandler(voice) {
|
||||
return function(err, req, res, next) {
|
||||
var parts = err.stack.split('\n')[1].split(/[()]/)[1].split(':')
|
||||
, filename = parts.shift()
|
||||
, basename = path.basename(filename)
|
||||
, lineno = parts.shift()
|
||||
, col = parts.shift()
|
||||
, lines = fs.readFileSync(filename, 'utf8').split('\n')
|
||||
, line = lines[lineno - 1].replace(/\./, ' ');
|
||||
|
||||
exec('say -v "' + voice + '" '
|
||||
+ err.message
|
||||
+ ' on line ' + lineno
|
||||
+ ' of ' + basename + '.'
|
||||
+ ' The contents of this line is '
|
||||
+ ' "' + line + '".');
|
||||
|
||||
res.send(500);
|
||||
}
|
||||
}
|
||||
|
||||
var app = express.createServer();
|
||||
|
||||
app.get('/', function(request, response){
|
||||
if (request.is(foo)) response.end('bar');
|
||||
});
|
||||
|
||||
app.use(errorHandler('Vicki'));
|
||||
|
||||
app.listen(3000);
|
||||
@@ -1,7 +1,4 @@
|
||||
|
||||
// Expose modules in ./support for demo purposes
|
||||
require.paths.unshift(__dirname + '/../../support');
|
||||
|
||||
/**
|
||||
* Module dependencies.
|
||||
*/
|
||||
|
||||
@@ -1,7 +1,4 @@
|
||||
|
||||
// Expose modules in ./support for demo purposes
|
||||
require.paths.unshift(__dirname + '/../../support');
|
||||
|
||||
/**
|
||||
* Module dependencies.
|
||||
*/
|
||||
@@ -15,7 +12,7 @@ var app = express.createServer(
|
||||
express.logger(),
|
||||
|
||||
// Required by session() middleware
|
||||
express.cookieDecoder(),
|
||||
express.cookieParser(),
|
||||
|
||||
// Populates:
|
||||
// - req.session
|
||||
|
||||
@@ -1,7 +1,4 @@
|
||||
|
||||
// Expose modules in ./support for demo purposes
|
||||
require.paths.unshift(__dirname + '/../../support');
|
||||
|
||||
/**
|
||||
* Module dependencies.
|
||||
*/
|
||||
|
||||
@@ -1,7 +1,4 @@
|
||||
|
||||
// Expose modules in ./support for demo purposes
|
||||
require.paths.unshift(__dirname + '/../../support');
|
||||
|
||||
/**
|
||||
* Module dependencies.
|
||||
*/
|
||||
|
||||
@@ -28,7 +28,7 @@ var exports = module.exports = connect.middleware;
|
||||
* Framework version.
|
||||
*/
|
||||
|
||||
exports.version = '2.3.1';
|
||||
exports.version = '2.3.6';
|
||||
|
||||
/**
|
||||
* Shortcut for `new Server(...)`.
|
||||
@@ -58,7 +58,8 @@ exports.Route = Route;
|
||||
* View extensions.
|
||||
*/
|
||||
|
||||
require('./view');
|
||||
exports.View =
|
||||
exports.view = require('./view');
|
||||
|
||||
/**
|
||||
* Response extensions.
|
||||
|
||||
11
lib/http.js
11
lib/http.js
@@ -12,7 +12,7 @@
|
||||
var qs = require('qs')
|
||||
, connect = require('connect')
|
||||
, router = require('./router')
|
||||
, methods = router.methods.concat(['del', 'all'])
|
||||
, methods = router.methods.concat('del', 'all')
|
||||
, view = require('./view')
|
||||
, url = require('url')
|
||||
, utils = connect.utils;
|
||||
@@ -87,7 +87,7 @@ app.init = function(middleware){
|
||||
if (middleware) middleware.forEach(self.use.bind(self));
|
||||
|
||||
// use router, expose as app.get(), etc
|
||||
var fn = router(function(app){ self.routes = app; });
|
||||
var fn = router(function(app){ self.routes = app; }, this);
|
||||
this.__defineGetter__('router', function(){
|
||||
this.__usedRouter = true;
|
||||
return fn;
|
||||
@@ -475,7 +475,7 @@ app.configure = function(env, fn){
|
||||
|
||||
// Generate routing methods
|
||||
|
||||
function generateMethod(method){
|
||||
methods.forEach(function(method){
|
||||
app[method] = function(path){
|
||||
var self = this;
|
||||
|
||||
@@ -493,10 +493,7 @@ function generateMethod(method){
|
||||
this.routes[method].apply(this, arguments);
|
||||
return this;
|
||||
};
|
||||
return arguments.callee;
|
||||
}
|
||||
|
||||
methods.forEach(generateMethod);
|
||||
});
|
||||
|
||||
// Alias delete as "del"
|
||||
|
||||
|
||||
@@ -269,7 +269,7 @@ req.is = function(type){
|
||||
if ('*' == type[0] && type[1] == contentType[1]) return true;
|
||||
if ('*' == type[1] && type[0] == contentType[0]) return true;
|
||||
}
|
||||
return ~contentType.indexOf(type);
|
||||
return !! ~contentType.indexOf(type);
|
||||
};
|
||||
|
||||
// Callback for isXMLHttpRequest / xhr
|
||||
|
||||
@@ -17,8 +17,9 @@ var fs = require('fs')
|
||||
, parseRange = require('./utils').parseRange
|
||||
, res = http.ServerResponse.prototype
|
||||
, send = connect.static.send
|
||||
, join = require('path').join
|
||||
, mime = require('mime');
|
||||
, mime = require('mime')
|
||||
, basename = path.basename
|
||||
, join = path.join;
|
||||
|
||||
/**
|
||||
* Send a response with the given `body` and optional `headers` and `status` code.
|
||||
@@ -141,7 +142,7 @@ res.sendfile = function(path, options, fn){
|
||||
options = {};
|
||||
}
|
||||
|
||||
options.path = path;
|
||||
options.path = encodeURIComponent(path);
|
||||
options.callback = fn;
|
||||
send(this.req, this, next, options);
|
||||
};
|
||||
@@ -180,7 +181,7 @@ res.contentType = function(type){
|
||||
res.attachment = function(filename){
|
||||
if (filename) this.contentType(filename);
|
||||
this.header('Content-Disposition', filename
|
||||
? 'attachment; filename="' + path.basename(filename) + '"'
|
||||
? 'attachment; filename="' + basename(filename) + '"'
|
||||
: 'attachment');
|
||||
return this;
|
||||
};
|
||||
|
||||
@@ -34,7 +34,7 @@ exports.methods = _methods;
|
||||
* @api private
|
||||
*/
|
||||
|
||||
function router(fn){
|
||||
function router(fn, app){
|
||||
var self = this
|
||||
, methods = {}
|
||||
, routes = {}
|
||||
@@ -79,12 +79,12 @@ function router(fn){
|
||||
middleware = utils.flatten(middleware);
|
||||
}
|
||||
|
||||
fn.middleware = middleware;
|
||||
|
||||
if (!path) throw new Error(name + ' route requires a path');
|
||||
if (!fn) throw new Error(name + ' route ' + path + ' requires a callback');
|
||||
|
||||
var route = new Route(name, path, fn);
|
||||
var options = { sensitive: app.enabled('case sensitive routes') };
|
||||
var route = new Route(name, path, fn, options);
|
||||
route.middleware = middleware;
|
||||
localRoutes.push(route);
|
||||
return self;
|
||||
};
|
||||
@@ -128,7 +128,7 @@ function router(fn){
|
||||
// route middleware
|
||||
i = 0;
|
||||
(function nextMiddleware(err){
|
||||
var fn = route.callback.middleware[i++];
|
||||
var fn = route.middleware[i++];
|
||||
if ('route' == err) {
|
||||
pass(req._route_index + 1);
|
||||
} else if (err) {
|
||||
@@ -238,6 +238,8 @@ function router(fn){
|
||||
return ret;
|
||||
};
|
||||
|
||||
router.routes = routes;
|
||||
|
||||
return router;
|
||||
}
|
||||
|
||||
|
||||
@@ -6,26 +6,65 @@
|
||||
*/
|
||||
|
||||
/**
|
||||
* Supported HTTP / WebDAV methods.
|
||||
* Hypertext Transfer Protocol -- HTTP/1.1
|
||||
* http://www.ietf.org/rfc/rfc2616.txt
|
||||
*/
|
||||
|
||||
module.exports = [
|
||||
'get'
|
||||
, 'post'
|
||||
, 'put'
|
||||
, 'delete'
|
||||
, 'connect'
|
||||
, 'options'
|
||||
, 'trace'
|
||||
, 'copy'
|
||||
, 'lock'
|
||||
, 'mkcol'
|
||||
, 'move'
|
||||
, 'propfind'
|
||||
, 'proppatch'
|
||||
, 'unlock'
|
||||
, 'report'
|
||||
, 'mkactivity'
|
||||
, 'checkout'
|
||||
, 'merge'
|
||||
];
|
||||
var RFC2616 = ['OPTIONS', 'GET', 'POST', 'PUT', 'DELETE', 'TRACE', 'CONNECT'];
|
||||
|
||||
/**
|
||||
* HTTP Extensions for Distributed Authoring -- WEBDAV
|
||||
* http://www.ietf.org/rfc/rfc2518.txt
|
||||
*/
|
||||
|
||||
var RFC2518 = ['PROPFIND', 'PROPPATCH', 'MKCOL', 'COPY', 'MOVE', 'LOCK', 'UNLOCK'];
|
||||
|
||||
/**
|
||||
* Versioning Extensions to WebDAV
|
||||
* http://www.ietf.org/rfc/rfc3253.txt
|
||||
*/
|
||||
|
||||
var RFC3253 = ['VERSION-CONTROL', 'REPORT', 'CHECKOUT', 'CHECKIN', 'UNCHECKOUT', 'MKWORKSPACE', 'UPDATE', 'LABEL', 'MERGE', 'BASELINE-CONTROL', 'MKACTIVITY'];
|
||||
|
||||
/**
|
||||
* Ordered Collections Protocol (WebDAV)
|
||||
* http://www.ietf.org/rfc/rfc3648.txt
|
||||
*/
|
||||
|
||||
var RFC3648 = ['ORDERPATCH'];
|
||||
|
||||
/**
|
||||
* Web Distributed Authoring and Versioning (WebDAV) Access Control Protocol
|
||||
* http://www.ietf.org/rfc/rfc3744.txt
|
||||
*/
|
||||
|
||||
var RFC3744 = ['ACL'];
|
||||
|
||||
/**
|
||||
* Web Distributed Authoring and Versioning (WebDAV) SEARCH
|
||||
* http://www.ietf.org/rfc/rfc5323.txt
|
||||
*/
|
||||
|
||||
var RFC5323 = ['SEARCH'];
|
||||
|
||||
/**
|
||||
* PATCH Method for HTTP
|
||||
* http://www.ietf.org/rfc/rfc5789.txt
|
||||
*/
|
||||
|
||||
var RFC5789 = ['PATCH'];
|
||||
|
||||
/**
|
||||
* Expose the methods.
|
||||
*/
|
||||
|
||||
module.exports = [].concat(
|
||||
RFC2616
|
||||
, RFC2518
|
||||
, RFC3253
|
||||
, RFC3648
|
||||
, RFC3744
|
||||
, RFC5323
|
||||
, RFC5789).map(function(method){
|
||||
return method.toLowerCase();
|
||||
});
|
||||
|
||||
@@ -13,18 +13,24 @@ module.exports = Route;
|
||||
|
||||
/**
|
||||
* Initialize `Route` with the given HTTP `method`, `path`,
|
||||
* and callback `fn`.
|
||||
* and callback `fn` and `options`.
|
||||
*
|
||||
* Options:
|
||||
*
|
||||
* - `sensitive` enable case-sensitive routes
|
||||
*
|
||||
* @param {String} method
|
||||
* @param {String} path
|
||||
* @param {Function} fn
|
||||
* @param {Object} options.
|
||||
* @api private
|
||||
*/
|
||||
|
||||
function Route(method, path, fn) {
|
||||
function Route(method, path, fn, options) {
|
||||
options = options || {};
|
||||
this.callback = fn;
|
||||
this.path = path;
|
||||
this.regexp = normalize(path, this.keys = []);
|
||||
this.regexp = normalize(path, this.keys = [], options.sensitive);
|
||||
this.method = method;
|
||||
}
|
||||
|
||||
@@ -39,11 +45,12 @@ function Route(method, path, fn) {
|
||||
*
|
||||
* @param {String|RegExp} path
|
||||
* @param {Array} keys
|
||||
* @param {Boolean} sensitive
|
||||
* @return {RegExp}
|
||||
* @api private
|
||||
*/
|
||||
|
||||
function normalize(path, keys) {
|
||||
function normalize(path, keys, sensitive) {
|
||||
if (path instanceof RegExp) return path;
|
||||
path = path
|
||||
.concat('/?')
|
||||
@@ -60,5 +67,5 @@ function normalize(path, keys) {
|
||||
})
|
||||
.replace(/([\/.])/g, '\\$1')
|
||||
.replace(/\*/g, '(.+)');
|
||||
return new RegExp('^' + path + '$', 'i');
|
||||
return new RegExp('^' + path + '$', sensitive ? '' : 'i');
|
||||
}
|
||||
150
lib/view.js
150
lib/view.js
@@ -33,6 +33,91 @@ exports = module.exports = View;
|
||||
|
||||
exports.register = View.register;
|
||||
|
||||
/**
|
||||
* Lookup and compile `view` with cache support by supplying
|
||||
* both the `cache` object and `cid` string,
|
||||
* followed by `options` passed to `exports.lookup()`.
|
||||
*
|
||||
* @param {String} view
|
||||
* @param {Object} cache
|
||||
* @param {Object} cid
|
||||
* @param {Object} options
|
||||
* @return {View}
|
||||
* @api private
|
||||
*/
|
||||
|
||||
exports.compile = function(view, cache, cid, options){
|
||||
if (cache && cid && cache[cid]) return cache[cid];
|
||||
|
||||
// lookup
|
||||
view = exports.lookup(view, options);
|
||||
|
||||
// hints
|
||||
if (!view.exists) {
|
||||
if (options.hint) hintAtViewPaths(view.original, options);
|
||||
var err = new Error('failed to locate view "' + view.original.view + '"');
|
||||
err.view = view.original;
|
||||
throw err;
|
||||
}
|
||||
|
||||
// compile
|
||||
view.fn = view.templateEngine.compile(view.contents, options);
|
||||
cache[cid] = view;
|
||||
|
||||
return view;
|
||||
};
|
||||
|
||||
/**
|
||||
* Lookup `view`, returning an instanceof `View`.
|
||||
*
|
||||
* Options:
|
||||
*
|
||||
* - `root` root directory path
|
||||
* - `defaultEngine` default template engine
|
||||
* - `parentView` parent `View` object
|
||||
* - `cache` cache object
|
||||
* - `cacheid` optional cache id
|
||||
*
|
||||
* Lookup:
|
||||
*
|
||||
* - partial `_<name>`
|
||||
* - any `<name>/index`
|
||||
* - non-layout `../<name>/index`
|
||||
* - any `<root>/<name>`
|
||||
* - partial `<root>/_<name>`
|
||||
*
|
||||
* @param {String} view
|
||||
* @param {Object} options
|
||||
* @return {View}
|
||||
* @api private
|
||||
*/
|
||||
|
||||
exports.lookup = function(view, options){
|
||||
var orig = view = new View(view, options);
|
||||
|
||||
// Try _ prefix ex: ./views/_<name>.jade
|
||||
if (partial) {
|
||||
view = new View(orig.prefixPath, options);
|
||||
if (!view.exists) view = orig;
|
||||
}
|
||||
|
||||
// Try index ex: ./views/user/index.jade
|
||||
if (!view.exists) view = new View(orig.indexPath, options);
|
||||
|
||||
// Try ../<name>/index ex: ../user/index.jade
|
||||
// when calling partial('user') within the same dir
|
||||
if (!view.exists && !options.isLayout) view = new View(orig.upIndexPath, options);
|
||||
|
||||
// Try root ex: <root>/user.jade
|
||||
if (!view.exists) view = new View(orig.rootPath, options);
|
||||
|
||||
// Try root _ prefix ex: <root>/_user.jade
|
||||
if (!view.exists && partial) view = new View(view.prefixPath, options);
|
||||
|
||||
view.original = orig;
|
||||
return view;
|
||||
};
|
||||
|
||||
/**
|
||||
* Partial render helper.
|
||||
*
|
||||
@@ -171,6 +256,7 @@ function renderPartial(res, view, options, parentLocals, parent){
|
||||
res.partial = function(view, options, fn){
|
||||
var app = this.app
|
||||
, options = options || {}
|
||||
, viewEngine = app.set('view engine')
|
||||
, parent = {};
|
||||
|
||||
// accept callback as second argument
|
||||
@@ -183,9 +269,7 @@ res.partial = function(view, options, fn){
|
||||
parent.dirname = app.set('views') || process.cwd() + '/views';
|
||||
|
||||
// utilize "view engine" option
|
||||
if (app.set('view engine')) {
|
||||
parent.extension = '.' + app.set('view engine');
|
||||
}
|
||||
if (viewEngine) parent.extension = '.' + viewEngine;
|
||||
|
||||
// render the partial
|
||||
try {
|
||||
@@ -256,11 +340,12 @@ res._render = function(view, opts, fn, parent, sub){
|
||||
, helpers = app._locals
|
||||
, dynamicHelpers = app.dynamicViewHelpers
|
||||
, viewOptions = app.set('view options')
|
||||
, cacheViews = app.enabled('view cache')
|
||||
, root = app.set('views') || process.cwd() + '/views';
|
||||
|
||||
// cache id
|
||||
var cid = view + (parent ? ':' + parent.path : '');
|
||||
var cid = app.enabled('view cache')
|
||||
? view + (parent ? ':' + parent.path : '')
|
||||
: false;
|
||||
|
||||
// merge "view options"
|
||||
if (viewOptions) merge(options, viewOptions);
|
||||
@@ -277,6 +362,9 @@ res._render = function(view, opts, fn, parent, sub){
|
||||
// status support
|
||||
if (options.status) this.statusCode = options.status;
|
||||
|
||||
// capture attempts
|
||||
options.attempts = [];
|
||||
|
||||
var partial = options.renderPartial
|
||||
, layout = options.layout;
|
||||
|
||||
@@ -325,46 +413,10 @@ res._render = function(view, opts, fn, parent, sub){
|
||||
return renderPartial(self, path, opts, options, view);
|
||||
};
|
||||
|
||||
// cached view
|
||||
if (app.cache[cid]) {
|
||||
view = app.cache[cid];
|
||||
options.filename = view.path;
|
||||
// resolve view
|
||||
} else {
|
||||
var orig = view = new View(view, options);
|
||||
|
||||
// Try _ prefix ex: ./views/_<name>.jade
|
||||
if (partial) {
|
||||
view = new View(orig.prefixPath, options);
|
||||
if (!view.exists) view = orig;
|
||||
}
|
||||
|
||||
// Try index ex: ./views/user/index.jade
|
||||
if (!view.exists) view = new View(orig.indexPath, options);
|
||||
|
||||
// Try ../<name>/index ex: ../user/index.jade
|
||||
// when calling partial('user') within the same dir
|
||||
if (!view.exists && !options.isLayout) view = new View(orig.upIndexPath, options);
|
||||
|
||||
// Try root ex: <root>/user.jade
|
||||
if (!view.exists) view = new View(orig.rootPath, options);
|
||||
|
||||
// Try root _ prefix ex: <root>/_user.jade
|
||||
if (!view.exists && partial) view = new View(view.prefixPath, options);
|
||||
|
||||
// Does not exist
|
||||
if (!view.exists) {
|
||||
if (app.enabled('hints')) hintAtViewPaths(orig, options);
|
||||
var err = new Error('failed to locate view "' + orig.view + '"');
|
||||
err.view = orig;
|
||||
throw err;
|
||||
}
|
||||
|
||||
options.filename = view.path;
|
||||
var engine = view.templateEngine;
|
||||
view.fn = engine.compile(view.contents, options)
|
||||
if (cacheViews) app.cache[cid] = view;
|
||||
}
|
||||
// View lookup
|
||||
options.hint = app.enabled('hints');
|
||||
view = exports.compile(view, app.cache, cid, options);
|
||||
options.filename = view.path;
|
||||
|
||||
// layout helper
|
||||
options.layout = function(path){
|
||||
@@ -403,10 +455,8 @@ res._render = function(view, opts, fn, parent, sub){
|
||||
function hintAtViewPaths(view, options) {
|
||||
console.error();
|
||||
console.error('failed to locate view "' + view.view + '", tried:');
|
||||
console.error(' - ' + new View(view.path, options).path);
|
||||
console.error(' - ' + new View(view.prefixPath, options).path);
|
||||
console.error(' - ' + new View(view.indexPath, options).path);
|
||||
if (!options.isLayout) console.error(' - ' + new View(view.upIndexPath, options).path);
|
||||
if (options.isLayout) console.error(' - ' + new View(view.rootPath, options).path);
|
||||
options.attempts.forEach(function(path){
|
||||
console.error(' - %s', path);
|
||||
});
|
||||
console.error();
|
||||
}
|
||||
@@ -49,6 +49,10 @@ function View(view, options) {
|
||||
this.name = this.basename.replace(this.extension, '');
|
||||
this.path = this.resolvePath();
|
||||
this.dirname = dirname(this.path);
|
||||
if (options.attempts) {
|
||||
if (!~options.attempts.indexOf(this.path))
|
||||
options.attempts.push(this.path);
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
|
||||
16
package.json
16
package.json
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"name": "express",
|
||||
"description": "Sinatra inspired web development framework",
|
||||
"version": "2.3.1",
|
||||
"version": "2.3.6",
|
||||
"author": "TJ Holowaychuk <tj@vision-media.ca>",
|
||||
"contributors": [
|
||||
{ "name": "TJ Holowaychuk", "email": "tj@vision-media.ca" },
|
||||
@@ -10,10 +10,22 @@
|
||||
{ "name": "Guillermo Rauch", "email": "rauchg@gmail.com" }
|
||||
],
|
||||
"dependencies": {
|
||||
"connect": ">= 1.4.0 < 2.0.0",
|
||||
"connect": ">= 1.4.1 < 2.0.0",
|
||||
"mime": ">= 0.0.1",
|
||||
"qs": ">= 0.0.6"
|
||||
},
|
||||
"devDependencies": {
|
||||
"connect-form": "0.2.1",
|
||||
"ejs": "0.4.2",
|
||||
"expresso": "0.7.2",
|
||||
"hamljs": "0.5.1",
|
||||
"jade": "0.11.0",
|
||||
"stylus": "0.13.0",
|
||||
"should": "0.2.1",
|
||||
"express-messages": "0.0.2",
|
||||
"node-markdown": ">= 0.0.1",
|
||||
"connect-redis": ">= 0.0.1"
|
||||
},
|
||||
"keywords": ["framework", "sinatra", "web", "rest", "restful"],
|
||||
"repository": "git://github.com/visionmedia/express",
|
||||
"main": "index",
|
||||
|
||||
Submodule support/connect deleted from af32d828a3
Submodule support/connect-form deleted from e861cc85d6
Submodule support/ejs deleted from 499c4815a5
Submodule support/expresso deleted from 855e0dea07
Submodule support/formidable deleted from 5d98e9c75c
Submodule support/haml deleted from 55bb6fdc79
Submodule support/jade deleted from bdeb8b9fb4
Submodule support/mime deleted from ade33a43be
Submodule support/qs deleted from 2b9796e54e
Submodule support/should deleted from 607f8734e8
@@ -435,5 +435,31 @@ module.exports = {
|
||||
{ url: '/' },
|
||||
{ body: 'restored' }
|
||||
);
|
||||
},
|
||||
|
||||
'test routes with same callback': function(){
|
||||
function handle(req, res) {
|
||||
res.send('got ' + req.string);
|
||||
}
|
||||
|
||||
var app = express.createServer();
|
||||
|
||||
app.get('/', function(req, res, next){
|
||||
req.string = '/';
|
||||
next();
|
||||
}, handle);
|
||||
|
||||
app.get('/another', function(req, res, next){
|
||||
req.string = '/another';
|
||||
next();
|
||||
}, handle);
|
||||
|
||||
assert.response(app,
|
||||
{ url: '/' },
|
||||
{ body: 'got /' });
|
||||
|
||||
assert.response(app,
|
||||
{ url: '/another' },
|
||||
{ body: 'got /another' });
|
||||
}
|
||||
};
|
||||
|
||||
1
test/fixtures/some random text file.txt
vendored
Normal file
1
test/fixtures/some random text file.txt
vendored
Normal file
@@ -0,0 +1 @@
|
||||
hello
|
||||
@@ -15,7 +15,7 @@ module.exports = {
|
||||
app.get('/html', function(req, res){
|
||||
res.send('<p>test</p>', { 'Content-Language': 'en' });
|
||||
});
|
||||
|
||||
|
||||
app.get('/json', function(req, res){
|
||||
res.header('X-Foo', 'bar');
|
||||
res.send({ foo: 'bar' }, { 'X-Foo': 'baz' }, 201);
|
||||
@@ -38,6 +38,10 @@ module.exports = {
|
||||
res.send(404);
|
||||
});
|
||||
|
||||
app.get('/status/text', function(req, res){
|
||||
res.send('Oh noes!', 404);
|
||||
});
|
||||
|
||||
app.get('/error', function(req, res){
|
||||
res.send('Oh shit!', { 'Content-Type': 'text/plain' }, 500);
|
||||
});
|
||||
@@ -122,7 +126,11 @@ module.exports = {
|
||||
'Content-Type': 'text/plain'
|
||||
, 'X-Foo': 'bar'
|
||||
}});
|
||||
|
||||
|
||||
assert.response(app,
|
||||
{ url: '/status/text' },
|
||||
{ body: 'Oh noes!', status: 404 });
|
||||
|
||||
assert.response(app,
|
||||
{ url: '/status' },
|
||||
{ body: 'Not Found'
|
||||
@@ -544,6 +552,10 @@ module.exports = {
|
||||
assert.equal(null, res.headers['content-disposition']);
|
||||
});
|
||||
|
||||
assert.response(app,
|
||||
{ url: '/some%20random%20text%20file.txt' },
|
||||
{ body: 'hello' });
|
||||
|
||||
beforeExit(function(){
|
||||
calls.should.equal(1);
|
||||
});
|
||||
|
||||
@@ -53,7 +53,7 @@ module.exports = {
|
||||
res.send(200);
|
||||
});
|
||||
|
||||
app.get('/user/:user', [allow('member')], [[restrictAge(18)]], function(req, res){
|
||||
app.get('/user/:user', [allow('member'), [[restrictAge(18)]]], function(req, res){
|
||||
res.send(200);
|
||||
});
|
||||
|
||||
@@ -241,5 +241,27 @@ module.exports = {
|
||||
app.match.get('/').should.have.be.empty;
|
||||
app.match.all('/user/123').should.have.length(3);
|
||||
app.match('/user/123').should.have.length(3);
|
||||
},
|
||||
|
||||
'test "case sensitive routes" setting': function(){
|
||||
var app = express.createServer();
|
||||
|
||||
app.enable('case sensitive routes');
|
||||
|
||||
app.get('/account', function(req, res){
|
||||
res.send('account');
|
||||
});
|
||||
|
||||
app.get('/Account', function(req, res){
|
||||
res.send('Account');
|
||||
});
|
||||
|
||||
assert.response(app,
|
||||
{ url: '/account' },
|
||||
{ body: 'account' });
|
||||
|
||||
assert.response(app,
|
||||
{ url: '/Account' },
|
||||
{ body: 'Account' });
|
||||
}
|
||||
};
|
||||
|
||||
@@ -105,6 +105,7 @@ module.exports = {
|
||||
'test #render()': function(){
|
||||
var app = create();
|
||||
app.set('view engine', 'jade');
|
||||
app.register('haml', require('hamljs'));
|
||||
|
||||
app.get('/', function(req, res){
|
||||
res.render('index.jade', { layout: false });
|
||||
|
||||
Reference in New Issue
Block a user