mirror of
https://github.com/expressjs/express.git
synced 2026-02-26 08:45:36 +00:00
Compare commits
68 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
4d8093302f | ||
|
|
4370908674 | ||
|
|
f0b679d02d | ||
|
|
c24463d829 | ||
|
|
656e214937 | ||
|
|
4b26bbde2d | ||
|
|
7fcc8b190d | ||
|
|
b326ae89df | ||
|
|
869ddd775c | ||
|
|
997fd74e8c | ||
|
|
e3e41a1118 | ||
|
|
6c8bcd5c4e | ||
|
|
95e63ec287 | ||
|
|
ebca5887cc | ||
|
|
8535d3a990 | ||
|
|
13184c4379 | ||
|
|
eaba4eeb70 | ||
|
|
ac56cf4606 | ||
|
|
6dea32cd18 | ||
|
|
5fab60bc6c | ||
|
|
881e1ba660 | ||
|
|
0e488c19df | ||
|
|
2262a18900 | ||
|
|
28c6952d1c | ||
|
|
01e3530a31 | ||
|
|
77c83d0c57 | ||
|
|
b4eaf89186 | ||
|
|
e4debea297 | ||
|
|
1c96e18d20 | ||
|
|
8bb013ec95 | ||
|
|
6c0031bfd8 | ||
|
|
ab6c189504 | ||
|
|
a12ae729bd | ||
|
|
d53a0cd91e | ||
|
|
eabd4564aa | ||
|
|
d40dc651f3 | ||
|
|
68290ee87a | ||
|
|
6614352563 | ||
|
|
0e5f2f84ea | ||
|
|
b1d0c19ca1 | ||
|
|
dfa7ee4732 | ||
|
|
e9539fc780 | ||
|
|
5f7a37ee51 | ||
|
|
ff3a368b2f | ||
|
|
ccc45a74f8 | ||
|
|
cd9d2ec6a9 | ||
|
|
ce7bbae007 | ||
|
|
6a5dd52deb | ||
|
|
6c2f7fb48d | ||
|
|
4dd970578a | ||
|
|
88dfd36eaa | ||
|
|
5759b3e9f5 | ||
|
|
c939a771c0 | ||
|
|
af1043844f | ||
|
|
dd763ec5b8 | ||
|
|
9c2c21aaaf | ||
|
|
366000184f | ||
|
|
4d1ee23f84 | ||
|
|
6f31218ecc | ||
|
|
6cd4859035 | ||
|
|
4f1cd4f73c | ||
|
|
0e5613363f | ||
|
|
7a7f18c20b | ||
|
|
b766aad112 | ||
|
|
7488e27609 | ||
|
|
bc9d854763 | ||
|
|
2e20a85810 | ||
|
|
a706408208 |
38
.gitignore
vendored
38
.gitignore
vendored
@@ -1,16 +1,26 @@
|
||||
coverage/
|
||||
.DS_Store
|
||||
*.seed
|
||||
# OS X
|
||||
.DS_Store*
|
||||
Icon?
|
||||
._*
|
||||
|
||||
# Windows
|
||||
Thumbs.db
|
||||
ehthumbs.db
|
||||
Desktop.ini
|
||||
|
||||
# Linux
|
||||
.directory
|
||||
*~
|
||||
|
||||
|
||||
# npm
|
||||
node_modules
|
||||
*.log
|
||||
*.csv
|
||||
*.dat
|
||||
*.out
|
||||
*.pid
|
||||
*.swp
|
||||
*.swo
|
||||
*.gz
|
||||
|
||||
|
||||
# Coveralls
|
||||
coverage
|
||||
|
||||
# Benchmarking
|
||||
benchmarks/graphs
|
||||
testing
|
||||
node_modules/
|
||||
testing
|
||||
test.js
|
||||
.idea
|
||||
|
||||
11
.npmignore
11
.npmignore
@@ -1,11 +0,0 @@
|
||||
.git*
|
||||
benchmarks/
|
||||
coverage/
|
||||
docs/
|
||||
examples/
|
||||
support/
|
||||
test/
|
||||
testing.js
|
||||
.DS_Store
|
||||
.travis.yml
|
||||
Contributing.md
|
||||
150
History.md
150
History.md
@@ -1,3 +1,77 @@
|
||||
4.10.5 / 2014-12-10
|
||||
===================
|
||||
|
||||
* Fix `res.send` double-calling `res.end` for `HEAD` requests
|
||||
* deps: accepts@~1.1.4
|
||||
- deps: mime-types@~2.0.4
|
||||
* deps: type-is@~1.5.4
|
||||
- deps: mime-types@~2.0.4
|
||||
|
||||
4.10.4 / 2014-11-24
|
||||
===================
|
||||
|
||||
* Fix `res.sendfile` logging standard write errors
|
||||
|
||||
4.10.3 / 2014-11-23
|
||||
===================
|
||||
|
||||
* Fix `res.sendFile` logging standard write errors
|
||||
* deps: etag@~1.5.1
|
||||
* deps: proxy-addr@~1.0.4
|
||||
- deps: ipaddr.js@0.1.5
|
||||
* deps: qs@2.3.3
|
||||
- Fix `arrayLimit` behavior
|
||||
|
||||
4.10.2 / 2014-11-09
|
||||
===================
|
||||
|
||||
* Correctly invoke async router callback asynchronously
|
||||
* deps: accepts@~1.1.3
|
||||
- deps: mime-types@~2.0.3
|
||||
* deps: type-is@~1.5.3
|
||||
- deps: mime-types@~2.0.3
|
||||
|
||||
4.10.1 / 2014-10-28
|
||||
===================
|
||||
|
||||
* Fix handling of URLs containing `://` in the path
|
||||
* deps: qs@2.3.2
|
||||
- Fix parsing of mixed objects and values
|
||||
|
||||
4.10.0 / 2014-10-23
|
||||
===================
|
||||
|
||||
* Add support for `app.set('views', array)`
|
||||
- Views are looked up in sequence in array of directories
|
||||
* Fix `res.send(status)` to mention `res.sendStatus(status)`
|
||||
* Fix handling of invalid empty URLs
|
||||
* Use `content-disposition` module for `res.attachment`/`res.download`
|
||||
- Sends standards-compliant `Content-Disposition` header
|
||||
- Full Unicode support
|
||||
* Use `path.resolve` in view lookup
|
||||
* deps: debug@~2.1.0
|
||||
- Implement `DEBUG_FD` env variable support
|
||||
* deps: depd@~1.0.0
|
||||
* deps: etag@~1.5.0
|
||||
- Improve string performance
|
||||
- Slightly improve speed for weak ETags over 1KB
|
||||
* deps: finalhandler@0.3.2
|
||||
- Terminate in progress response only on error
|
||||
- Use `on-finished` to determine request status
|
||||
- deps: debug@~2.1.0
|
||||
- deps: on-finished@~2.1.1
|
||||
* deps: on-finished@~2.1.1
|
||||
- Fix handling of pipelined requests
|
||||
* deps: qs@2.3.0
|
||||
- Fix parsing of mixed implicit and explicit arrays
|
||||
* deps: send@0.10.1
|
||||
- deps: debug@~2.1.0
|
||||
- deps: depd@~1.0.0
|
||||
- deps: etag@~1.5.0
|
||||
- deps: on-finished@~2.1.1
|
||||
* deps: serve-static@~1.7.1
|
||||
- deps: send@0.10.1
|
||||
|
||||
4.9.8 / 2014-10-17
|
||||
==================
|
||||
|
||||
@@ -534,6 +608,82 @@
|
||||
- `app.route()` - Proxy to the app's `Router#route()` method to create a new route
|
||||
- Router & Route - public API
|
||||
|
||||
3.18.4 / 2014-11-23
|
||||
===================
|
||||
|
||||
* deps: connect@2.27.4
|
||||
- deps: body-parser@~1.9.3
|
||||
- deps: compression@~1.2.1
|
||||
- deps: errorhandler@~1.2.3
|
||||
- deps: express-session@~1.9.2
|
||||
- deps: qs@2.3.3
|
||||
- deps: serve-favicon@~2.1.7
|
||||
- deps: serve-static@~1.5.1
|
||||
- deps: type-is@~1.5.3
|
||||
* deps: etag@~1.5.1
|
||||
* deps: proxy-addr@~1.0.4
|
||||
- deps: ipaddr.js@0.1.5
|
||||
|
||||
3.18.3 / 2014-11-09
|
||||
===================
|
||||
|
||||
* deps: connect@2.27.3
|
||||
- Correctly invoke async callback asynchronously
|
||||
- deps: csurf@~1.6.3
|
||||
|
||||
3.18.2 / 2014-10-28
|
||||
===================
|
||||
|
||||
* deps: connect@2.27.2
|
||||
- Fix handling of URLs containing `://` in the path
|
||||
- deps: body-parser@~1.9.2
|
||||
- deps: qs@2.3.2
|
||||
|
||||
3.18.1 / 2014-10-22
|
||||
===================
|
||||
|
||||
* Fix internal `utils.merge` deprecation warnings
|
||||
* deps: connect@2.27.1
|
||||
- deps: body-parser@~1.9.1
|
||||
- deps: express-session@~1.9.1
|
||||
- deps: finalhandler@0.3.2
|
||||
- deps: morgan@~1.4.1
|
||||
- deps: qs@2.3.0
|
||||
- deps: serve-static@~1.7.1
|
||||
* deps: send@0.10.1
|
||||
- deps: on-finished@~2.1.1
|
||||
|
||||
3.18.0 / 2014-10-17
|
||||
===================
|
||||
|
||||
* Use `content-disposition` module for `res.attachment`/`res.download`
|
||||
- Sends standards-compliant `Content-Disposition` header
|
||||
- Full Unicode support
|
||||
* Use `etag` module to generate `ETag` headers
|
||||
* deps: connect@2.27.0
|
||||
- Use `http-errors` module for creating errors
|
||||
- Use `utils-merge` module for merging objects
|
||||
- deps: body-parser@~1.9.0
|
||||
- deps: compression@~1.2.0
|
||||
- deps: connect-timeout@~1.4.0
|
||||
- deps: debug@~2.1.0
|
||||
- deps: depd@~1.0.0
|
||||
- deps: express-session@~1.9.0
|
||||
- deps: finalhandler@0.3.1
|
||||
- deps: method-override@~2.3.0
|
||||
- deps: morgan@~1.4.0
|
||||
- deps: response-time@~2.2.0
|
||||
- deps: serve-favicon@~2.1.6
|
||||
- deps: serve-index@~1.5.0
|
||||
- deps: serve-static@~1.7.0
|
||||
* deps: debug@~2.1.0
|
||||
- Implement `DEBUG_FD` env variable support
|
||||
* deps: depd@~1.0.0
|
||||
* deps: send@0.10.0
|
||||
- deps: debug@~2.1.0
|
||||
- deps: depd@~1.0.0
|
||||
- deps: etag@~1.5.0
|
||||
|
||||
3.17.8 / 2014-10-15
|
||||
===================
|
||||
|
||||
|
||||
99
Readme.md
99
Readme.md
@@ -2,10 +2,10 @@
|
||||
|
||||
Fast, unopinionated, minimalist web framework for [node](http://nodejs.org).
|
||||
|
||||
[](https://www.npmjs.org/package/express)
|
||||
[](https://travis-ci.org/strongloop/express)
|
||||
[](https://coveralls.io/r/strongloop/express)
|
||||
[](https://www.gittip.com/dougwilson/)
|
||||
[![NPM Version][npm-image]][npm-url]
|
||||
[![NPM Downloads][downloads-image]][downloads-url]
|
||||
[![Build Status][travis-image]][travis-url]
|
||||
[![Test Coverage][coveralls-image]][coveralls-url]
|
||||
|
||||
```js
|
||||
var express = require('express')
|
||||
@@ -18,14 +18,34 @@ app.get('/', function (req, res) {
|
||||
app.listen(3000)
|
||||
```
|
||||
|
||||
**PROTIP** Be sure to read [Migrating from 3.x to 4.x](https://github.com/strongloop/express/wiki/Migrating-from-3.x-to-4.x) as well as [New features in 4.x](https://github.com/strongloop/express/wiki/New-features-in-4.x).
|
||||
|
||||
### Installation
|
||||
|
||||
```bash
|
||||
$ npm install express
|
||||
```
|
||||
|
||||
## Features
|
||||
|
||||
* Robust routing
|
||||
* Focus on high performance
|
||||
* Super-high test coverage
|
||||
* HTTP helpers (redirection, caching, etc)
|
||||
* View system supporting 14+ template engines
|
||||
* Content negotiation
|
||||
* Executable for generating applications quickly
|
||||
|
||||
## Docs & Community
|
||||
|
||||
* [Website and Documentation](http://expressjs.com/) - [[website repo](https://github.com/strongloop/expressjs.com)]
|
||||
* [#express](https://webchat.freenode.net/?channels=express) on freenode IRC
|
||||
* [Github Organization](https://github.com/expressjs) for Official Middleware & Modules
|
||||
* Visit the [Wiki](https://github.com/strongloop/express/wiki)
|
||||
* [Google Group](https://groups.google.com/group/express-js) for discussion
|
||||
* [Русскоязычная документация](http://jsman.ru/express/)
|
||||
* [한국어 문서](http://expressjs.kr) - [[website repo](https://github.com/Hanul/expressjs.kr)]
|
||||
|
||||
**PROTIP** Be sure to read [Migrating from 3.x to 4.x](https://github.com/strongloop/express/wiki/Migrating-from-3.x-to-4.x) as well as [New features in 4.x](https://github.com/strongloop/express/wiki/New-features-in-4.x).
|
||||
|
||||
## Quick Start
|
||||
|
||||
The quickest way to get started with express is to utilize the executable [`express(1)`](https://github.com/expressjs/generator) to generate an application as shown below:
|
||||
@@ -54,16 +74,6 @@ $ npm install
|
||||
$ npm start
|
||||
```
|
||||
|
||||
## Features
|
||||
|
||||
* Robust routing
|
||||
* HTTP helpers (redirection, caching, etc)
|
||||
* View system supporting 14+ template engines
|
||||
* Content negotiation
|
||||
* Focus on high performance
|
||||
* Executable for generating applications quickly
|
||||
* High test coverage
|
||||
|
||||
## Philosophy
|
||||
|
||||
The Express philosophy is to provide small, robust tooling for HTTP servers, making
|
||||
@@ -71,23 +81,12 @@ $ npm start
|
||||
HTTP APIs.
|
||||
|
||||
Express does not force you to use any specific ORM or template engine. With support for over
|
||||
14 template engines via [Consolidate.js](https://github.com/visionmedia/consolidate.js),
|
||||
14 template engines via [Consolidate.js](https://github.com/tj/consolidate.js),
|
||||
you can quickly craft your perfect framework.
|
||||
|
||||
## More Information
|
||||
## Examples
|
||||
|
||||
* [Website and Documentation](http://expressjs.com/) - [[website repo](https://github.com/strongloop/expressjs.com)]
|
||||
* [Github Organization](https://github.com/expressjs) for Official Middleware & Modules
|
||||
* [#express](https://webchat.freenode.net/?channels=express) on freenode IRC
|
||||
* Visit the [Wiki](https://github.com/strongloop/express/wiki)
|
||||
* [Google Group](https://groups.google.com/group/express-js) for discussion
|
||||
* [Русскоязычная документация](http://jsman.ru/express/)
|
||||
* [한국어 문서](http://expressjs.kr) - [[website repo](https://github.com/Hanul/expressjs.kr)]
|
||||
* 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 dependencies:
|
||||
To view the examples, clone the Express repo & install the dependancies:
|
||||
|
||||
```bash
|
||||
$ git clone git://github.com/strongloop/express.git --depth 1
|
||||
@@ -97,32 +96,40 @@ $ npm install
|
||||
|
||||
Then run whichever example you want:
|
||||
|
||||
$ node examples/content-negotiation
|
||||
```bash
|
||||
$ node examples/content-negotiation
|
||||
```
|
||||
|
||||
You can also view live examples here:
|
||||
## Tests
|
||||
|
||||
<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 install the dependancies, then run `npm test`:
|
||||
|
||||
```bash
|
||||
$ npm install
|
||||
```
|
||||
|
||||
Then run the tests:
|
||||
|
||||
```bash
|
||||
$ npm test
|
||||
```
|
||||
|
||||
### Contributors
|
||||
### People
|
||||
|
||||
* Author: [TJ Holowaychuk](https://github.com/visionmedia)
|
||||
* Lead Maintainer: [Douglas Christopher Wilson](https://github.com/dougwilson)
|
||||
* [All Contributors](https://github.com/strongloop/express/graphs/contributors)
|
||||
The original author of Express is [TJ Holowaychuk](https://github.com/tj) [![TJ's Gratipay][gratipay-image-visionmedia]][gratipay-url-visionmedia]
|
||||
|
||||
The current lead maintainer is [Douglas Christopher Wilson](https://github.com/dougwilson) [![Doug's Gratipay][gratipay-image-dougwilson]][gratipay-url-dougwilson]
|
||||
|
||||
[List of all contributors](https://github.com/strongloop/express/graphs/contributors)
|
||||
|
||||
### License
|
||||
|
||||
[MIT](LICENSE)
|
||||
|
||||
[npm-image]: https://img.shields.io/npm/v/express.svg?style=flat
|
||||
[npm-url]: https://npmjs.org/package/express
|
||||
[downloads-image]: https://img.shields.io/npm/dm/express.svg?style=flat
|
||||
[downloads-url]: https://npmjs.org/package/express
|
||||
[travis-image]: https://img.shields.io/travis/strongloop/express.svg?style=flat
|
||||
[travis-url]: https://travis-ci.org/strongloop/express
|
||||
[coveralls-image]: https://img.shields.io/coveralls/strongloop/express.svg?style=flat
|
||||
[coveralls-url]: https://coveralls.io/r/strongloop/express?branch=master
|
||||
[gratipay-image-visionmedia]: https://img.shields.io/gratipay/visionmedia.svg?style=flat
|
||||
[gratipay-url-visionmedia]: https://gratipay.com/visionmedia/
|
||||
[gratipay-image-dougwilson]: https://img.shields.io/gratipay/dougwilson.svg?style=flat
|
||||
[gratipay-url-dougwilson]: https://gratipay.com/dougwilson/
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
|
||||
// check out https://github.com/visionmedia/node-pwd
|
||||
// check out https://github.com/tj/node-pwd
|
||||
|
||||
/**
|
||||
* Module dependencies.
|
||||
|
||||
@@ -1,48 +0,0 @@
|
||||
/**
|
||||
* Module dependencies.
|
||||
*/
|
||||
|
||||
var express = require('../..');
|
||||
var logger = require('morgan');
|
||||
var app = express();
|
||||
var bodyParser = require('body-parser');
|
||||
var api = express();
|
||||
|
||||
// app middleware
|
||||
|
||||
app.use(express.static(__dirname + '/public'));
|
||||
|
||||
// api middleware
|
||||
|
||||
api.use(logger('dev'));
|
||||
api.use(bodyParser.json());
|
||||
|
||||
/**
|
||||
* CORS support.
|
||||
*/
|
||||
|
||||
api.all('*', function(req, res, next){
|
||||
if (!req.get('Origin')) return next();
|
||||
// use "*" here to accept any origin
|
||||
res.set('Access-Control-Allow-Origin', 'http://localhost:3000');
|
||||
res.set('Access-Control-Allow-Methods', 'PUT');
|
||||
res.set('Access-Control-Allow-Headers', 'X-Requested-With, Content-Type');
|
||||
// res.set('Access-Control-Allow-Max-Age', 3600);
|
||||
if ('OPTIONS' == req.method) return res.send(200);
|
||||
next();
|
||||
});
|
||||
|
||||
/**
|
||||
* PUT an existing user.
|
||||
*/
|
||||
|
||||
api.put('/user/:id', function(req, res){
|
||||
console.log(req.body);
|
||||
res.send(204);
|
||||
});
|
||||
|
||||
app.listen(3000);
|
||||
api.listen(3001);
|
||||
|
||||
console.log('app listening on 3000');
|
||||
console.log('api listening on 3001');
|
||||
@@ -1,12 +0,0 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<body>
|
||||
<script>
|
||||
var req = new XMLHttpRequest;
|
||||
req.open('PUT', 'http://localhost:3001/user/1', false);
|
||||
req.setRequestHeader('Content-Type', 'application/json');
|
||||
req.send('{"name":"tobi","species":"ferret"}');
|
||||
console.log(req.responseText);
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
13
examples/multi-router/controllers/api_v1.js
Normal file
13
examples/multi-router/controllers/api_v1.js
Normal file
@@ -0,0 +1,13 @@
|
||||
var express = require('../../..');
|
||||
|
||||
var apiv1 = express.Router();
|
||||
|
||||
apiv1.get('/', function(req, res) {
|
||||
res.send('Hello from APIv1 root route.');
|
||||
});
|
||||
|
||||
apiv1.get('/users', function(req, res) {
|
||||
res.send('List of APIv1 users.');
|
||||
});
|
||||
|
||||
module.exports = apiv1;
|
||||
13
examples/multi-router/controllers/api_v2.js
Normal file
13
examples/multi-router/controllers/api_v2.js
Normal file
@@ -0,0 +1,13 @@
|
||||
var express = require('../../..');
|
||||
|
||||
var apiv2 = express.Router();
|
||||
|
||||
apiv2.get('/', function(req, res) {
|
||||
res.send('Hello from APIv2 root route.');
|
||||
});
|
||||
|
||||
apiv2.get('/users', function(req, res) {
|
||||
res.send('List of APIv2 users.');
|
||||
});
|
||||
|
||||
module.exports = apiv2;
|
||||
16
examples/multi-router/index.js
Normal file
16
examples/multi-router/index.js
Normal file
@@ -0,0 +1,16 @@
|
||||
var express = require('../..');
|
||||
|
||||
var app = module.exports = express();
|
||||
|
||||
app.use('/api/v1', require('./controllers/api_v1'));
|
||||
app.use('/api/v2', require('./controllers/api_v2'));
|
||||
|
||||
app.get('/', function(req, res) {
|
||||
res.send('Hello form root route.');
|
||||
});
|
||||
|
||||
/* istanbul ignore next */
|
||||
if (!module.parent) {
|
||||
app.listen(3000);
|
||||
console.log('Express started on port 3000');
|
||||
}
|
||||
@@ -4,7 +4,6 @@
|
||||
|
||||
var finalhandler = require('finalhandler');
|
||||
var flatten = require('./utils').flatten;
|
||||
var mixin = require('utils-merge');
|
||||
var Router = require('./router');
|
||||
var methods = require('methods');
|
||||
var middleware = require('./middleware/init');
|
||||
@@ -16,6 +15,7 @@ var compileETag = require('./utils').compileETag;
|
||||
var compileQueryParser = require('./utils').compileQueryParser;
|
||||
var compileTrust = require('./utils').compileTrust;
|
||||
var deprecate = require('depd')('express');
|
||||
var merge = require('utils-merge');
|
||||
var resolve = require('path').resolve;
|
||||
var slice = Array.prototype.slice;
|
||||
|
||||
@@ -154,7 +154,6 @@ app.handle = function(req, res, done) {
|
||||
app.use = function use(fn) {
|
||||
var offset = 0;
|
||||
var path = '/';
|
||||
var self = this;
|
||||
|
||||
// default path to '/'
|
||||
// disambiguate app.use([fn])
|
||||
@@ -190,7 +189,7 @@ app.use = function use(fn) {
|
||||
|
||||
debug('.use app under %s', path);
|
||||
fn.mountpath = path;
|
||||
fn.parent = self;
|
||||
fn.parent = this;
|
||||
|
||||
// restore .app property on req and res
|
||||
router.use(path, function mounted_app(req, res, next) {
|
||||
@@ -203,8 +202,8 @@ app.use = function use(fn) {
|
||||
});
|
||||
|
||||
// mounted an app
|
||||
fn.emit('mount', self);
|
||||
});
|
||||
fn.emit('mount', this);
|
||||
}, this);
|
||||
|
||||
return this;
|
||||
};
|
||||
@@ -247,7 +246,7 @@ app.route = function(path){
|
||||
* so if you're using ".ejs" extensions you dont need to do anything.
|
||||
*
|
||||
* Some template engines do not follow this convention, the
|
||||
* [Consolidate.js](https://github.com/visionmedia/consolidate.js)
|
||||
* [Consolidate.js](https://github.com/tj/consolidate.js)
|
||||
* library was created to map all of node's popular template
|
||||
* engines to follow this convention, thus allowing them to
|
||||
* work seamlessly within Express.
|
||||
@@ -278,17 +277,16 @@ app.engine = function(ext, fn){
|
||||
*/
|
||||
|
||||
app.param = function(name, fn){
|
||||
var self = this;
|
||||
self.lazyrouter();
|
||||
this.lazyrouter();
|
||||
|
||||
if (Array.isArray(name)) {
|
||||
name.forEach(function(key) {
|
||||
self.param(key, fn);
|
||||
});
|
||||
this.param(key, fn);
|
||||
}, this);
|
||||
return this;
|
||||
}
|
||||
|
||||
self._router.param(name, fn);
|
||||
this._router.param(name, fn);
|
||||
return this;
|
||||
};
|
||||
|
||||
@@ -488,13 +486,15 @@ app.render = function(name, options, fn){
|
||||
}
|
||||
|
||||
// merge app.locals
|
||||
mixin(opts, this.locals);
|
||||
merge(opts, this.locals);
|
||||
|
||||
// merge options._locals
|
||||
if (options._locals) mixin(opts, options._locals);
|
||||
if (options._locals) {
|
||||
merge(opts, options._locals);
|
||||
}
|
||||
|
||||
// merge options
|
||||
mixin(opts, options);
|
||||
merge(opts, options);
|
||||
|
||||
// set .cache unless explicitly provided
|
||||
opts.cache = null == opts.cache
|
||||
@@ -513,7 +513,10 @@ app.render = function(name, options, fn){
|
||||
});
|
||||
|
||||
if (!view.path) {
|
||||
var err = new Error('Failed to lookup view "' + name + '" in views directory "' + view.root + '"');
|
||||
var dirs = Array.isArray(view.root) && view.root.length > 1
|
||||
? 'directories "' + view.root.slice(0, -1).join('", "') + '" or "' + view.root[view.root.length - 1] + '"'
|
||||
: 'directory "' + view.root + '"'
|
||||
var err = new Error('Failed to lookup view "' + name + '" in views ' + dirs);
|
||||
err.view = view;
|
||||
return fn(err);
|
||||
}
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
*/
|
||||
|
||||
var EventEmitter = require('events').EventEmitter;
|
||||
var mixin = require('utils-merge');
|
||||
var mixin = require('merge-descriptors');
|
||||
var proto = require('./application');
|
||||
var Route = require('./router/route');
|
||||
var Router = require('./router');
|
||||
|
||||
@@ -2,18 +2,18 @@
|
||||
* Module dependencies.
|
||||
*/
|
||||
|
||||
var contentDisposition = require('content-disposition');
|
||||
var deprecate = require('depd')('express');
|
||||
var escapeHtml = require('escape-html');
|
||||
var http = require('http');
|
||||
var isAbsolute = require('./utils').isAbsolute;
|
||||
var onFinished = require('on-finished');
|
||||
var path = require('path');
|
||||
var mixin = require('utils-merge');
|
||||
var merge = require('utils-merge');
|
||||
var sign = require('cookie-signature').sign;
|
||||
var normalizeType = require('./utils').normalizeType;
|
||||
var normalizeTypes = require('./utils').normalizeTypes;
|
||||
var setCharset = require('./utils').setCharset;
|
||||
var contentDisposition = require('./utils').contentDisposition;
|
||||
var statusCodes = http.STATUS_CODES;
|
||||
var cookie = require('cookie');
|
||||
var send = require('send');
|
||||
@@ -109,7 +109,7 @@ res.send = function send(body) {
|
||||
this.type('txt');
|
||||
}
|
||||
|
||||
deprecate('res.send(status): Use res.status(status).end() instead');
|
||||
deprecate('res.send(status): Use res.sendStatus(status) instead');
|
||||
this.statusCode = chunk;
|
||||
chunk = http.STATUS_CODES[chunk];
|
||||
}
|
||||
@@ -182,14 +182,14 @@ res.send = function send(body) {
|
||||
chunk = '';
|
||||
}
|
||||
|
||||
// skip body for HEAD
|
||||
if (isHead) {
|
||||
// skip body for HEAD
|
||||
this.end();
|
||||
} else {
|
||||
// respond
|
||||
this.end(chunk, encoding);
|
||||
}
|
||||
|
||||
// respond
|
||||
this.end(chunk, encoding);
|
||||
|
||||
return this;
|
||||
};
|
||||
|
||||
@@ -398,8 +398,8 @@ res.sendFile = function sendFile(path, options, fn) {
|
||||
if (fn) return fn(err);
|
||||
if (err && err.code === 'EISDIR') return next();
|
||||
|
||||
// next() all but aborted errors
|
||||
if (err && err.code !== 'ECONNABORT') {
|
||||
// next() all but write errors
|
||||
if (err && err.code !== 'ECONNABORT' && err.syscall !== 'write') {
|
||||
next(err);
|
||||
}
|
||||
});
|
||||
@@ -467,8 +467,8 @@ res.sendfile = function(path, options, fn){
|
||||
if (fn) return fn(err);
|
||||
if (err && err.code === 'EISDIR') return next();
|
||||
|
||||
// next() all but aborted errors
|
||||
if (err && err.code !== 'ECONNABORT') {
|
||||
// next() all but write errors
|
||||
if (err && err.code !== 'ECONNABORT' && err.syscall !== 'write') {
|
||||
next(err);
|
||||
}
|
||||
});
|
||||
@@ -626,9 +626,13 @@ res.format = function(obj){
|
||||
* @api public
|
||||
*/
|
||||
|
||||
res.attachment = function(filename){
|
||||
if (filename) this.type(extname(filename));
|
||||
res.attachment = function attachment(filename) {
|
||||
if (filename) {
|
||||
this.type(extname(filename));
|
||||
}
|
||||
|
||||
this.set('Content-Disposition', contentDisposition(filename));
|
||||
|
||||
return this;
|
||||
};
|
||||
|
||||
@@ -692,7 +696,7 @@ res.get = function(field){
|
||||
res.clearCookie = function(name, options){
|
||||
var opts = { expires: new Date(1), path: '/' };
|
||||
return this.cookie(name, '', options
|
||||
? mixin(opts, options)
|
||||
? merge(opts, options)
|
||||
: opts);
|
||||
};
|
||||
|
||||
@@ -721,7 +725,7 @@ res.clearCookie = function(name, options){
|
||||
*/
|
||||
|
||||
res.cookie = function(name, val, options){
|
||||
options = mixin({}, options);
|
||||
options = merge({}, options);
|
||||
var secret = this.req.secret;
|
||||
var signed = options.signed;
|
||||
if (signed && !secret) throw new Error('cookieParser("secret") required for signed cookies');
|
||||
|
||||
@@ -126,7 +126,7 @@ proto.handle = function(req, res, done) {
|
||||
|
||||
var search = 1 + req.url.indexOf('?');
|
||||
var pathlength = search ? search - 1 : req.url.length;
|
||||
var fqdn = 1 + req.url.substr(0, pathlength).indexOf('://');
|
||||
var fqdn = req.url[0] !== '/' && 1 + req.url.substr(0, pathlength).indexOf('://');
|
||||
var protohost = fqdn ? req.url.substr(0, req.url.indexOf('/', 2 + fqdn)) : '';
|
||||
var idx = 0;
|
||||
var removed = '';
|
||||
@@ -183,7 +183,8 @@ proto.handle = function(req, res, done) {
|
||||
}
|
||||
|
||||
if (!layer) {
|
||||
return done(layerError);
|
||||
setImmediate(done, layerError);
|
||||
return;
|
||||
}
|
||||
|
||||
self.match_layer(layer, req, res, function (err, path) {
|
||||
@@ -409,7 +410,6 @@ proto.process_params = function(layer, called, req, res, done) {
|
||||
proto.use = function use(fn) {
|
||||
var offset = 0;
|
||||
var path = '/';
|
||||
var self = this;
|
||||
|
||||
// default path to '/'
|
||||
// disambiguate router.use([fn])
|
||||
@@ -442,15 +442,15 @@ proto.use = function use(fn) {
|
||||
debug('use %s %s', path, fn.name || '<anonymous>');
|
||||
|
||||
var layer = new Layer(path, {
|
||||
sensitive: self.caseSensitive,
|
||||
sensitive: this.caseSensitive,
|
||||
strict: false,
|
||||
end: false
|
||||
}, fn);
|
||||
|
||||
layer.route = undefined;
|
||||
|
||||
self.stack.push(layer);
|
||||
});
|
||||
this.stack.push(layer);
|
||||
}, this);
|
||||
|
||||
return this;
|
||||
};
|
||||
|
||||
@@ -95,6 +95,13 @@ Layer.prototype.handle_request = function handle(req, res, next) {
|
||||
*/
|
||||
|
||||
Layer.prototype.match = function match(path) {
|
||||
if (path == null) {
|
||||
// no path, nothing matches
|
||||
this.params = undefined;
|
||||
this.path = undefined;
|
||||
return false;
|
||||
}
|
||||
|
||||
if (this.regexp.fast_slash) {
|
||||
// fast path non-ending match for / (everything matches)
|
||||
this.params = {};
|
||||
|
||||
@@ -1,56 +0,0 @@
|
||||
|
||||
/**
|
||||
* Expose `Layer`.
|
||||
*/
|
||||
|
||||
module.exports = Match;
|
||||
|
||||
function Match(layer, path, params) {
|
||||
this.layer = layer;
|
||||
this.params = {};
|
||||
this.path = path || '';
|
||||
|
||||
if (!params) {
|
||||
return this;
|
||||
}
|
||||
|
||||
var keys = layer.keys;
|
||||
var n = 0;
|
||||
var prop;
|
||||
var key;
|
||||
var val;
|
||||
|
||||
for (var i = 0; i < params.length; i++) {
|
||||
key = keys[i];
|
||||
val = decode_param(params[i]);
|
||||
prop = key
|
||||
? key.name
|
||||
: n++;
|
||||
|
||||
this.params[prop] = val;
|
||||
}
|
||||
|
||||
return this;
|
||||
};
|
||||
|
||||
/**
|
||||
* Decode param value.
|
||||
*
|
||||
* @param {string} val
|
||||
* @return {string}
|
||||
* @api private
|
||||
*/
|
||||
|
||||
function decode_param(val){
|
||||
if (typeof val !== 'string') {
|
||||
return val;
|
||||
}
|
||||
|
||||
try {
|
||||
return decodeURIComponent(val);
|
||||
} catch (e) {
|
||||
var err = new TypeError("Failed to decode param '" + val + "'");
|
||||
err.status = 400;
|
||||
throw err;
|
||||
}
|
||||
}
|
||||
@@ -131,7 +131,6 @@ Route.prototype.dispatch = function(req, res, done){
|
||||
*/
|
||||
|
||||
Route.prototype.all = function(){
|
||||
var self = this;
|
||||
var callbacks = utils.flatten([].slice.call(arguments));
|
||||
callbacks.forEach(function(fn) {
|
||||
if (typeof fn !== 'function') {
|
||||
@@ -143,16 +142,15 @@ Route.prototype.all = function(){
|
||||
var layer = Layer('/', {}, fn);
|
||||
layer.method = undefined;
|
||||
|
||||
self.methods._all = true;
|
||||
self.stack.push(layer);
|
||||
});
|
||||
this.methods._all = true;
|
||||
this.stack.push(layer);
|
||||
}, this);
|
||||
|
||||
return self;
|
||||
return this;
|
||||
};
|
||||
|
||||
methods.forEach(function(method){
|
||||
Route.prototype[method] = function(){
|
||||
var self = this;
|
||||
var callbacks = utils.flatten([].slice.call(arguments));
|
||||
|
||||
callbacks.forEach(function(fn) {
|
||||
@@ -162,14 +160,14 @@ methods.forEach(function(method){
|
||||
throw new Error(msg);
|
||||
}
|
||||
|
||||
debug('%s %s', method, self.path);
|
||||
debug('%s %s', method, this.path);
|
||||
|
||||
var layer = Layer('/', {}, fn);
|
||||
layer.method = method;
|
||||
|
||||
self.methods[method] = true;
|
||||
self.stack.push(layer);
|
||||
});
|
||||
return self;
|
||||
this.methods[method] = true;
|
||||
this.stack.push(layer);
|
||||
}, this);
|
||||
return this;
|
||||
};
|
||||
});
|
||||
|
||||
24
lib/utils.js
24
lib/utils.js
@@ -2,6 +2,8 @@
|
||||
* Module dependencies.
|
||||
*/
|
||||
|
||||
var contentDisposition = require('content-disposition');
|
||||
var deprecate = require('depd')('express');
|
||||
var mime = require('send').mime;
|
||||
var basename = require('path').basename;
|
||||
var etag = require('etag');
|
||||
@@ -22,9 +24,9 @@ var typer = require('media-typer');
|
||||
exports.etag = function (body, encoding) {
|
||||
var buf = !Buffer.isBuffer(body)
|
||||
? new Buffer(body, encoding)
|
||||
: body
|
||||
: body;
|
||||
|
||||
return etag(buf, {weak: false})
|
||||
return etag(buf, {weak: false});
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -39,9 +41,9 @@ exports.etag = function (body, encoding) {
|
||||
exports.wetag = function wetag(body, encoding){
|
||||
var buf = !Buffer.isBuffer(body)
|
||||
? new Buffer(body, encoding)
|
||||
: body
|
||||
: body;
|
||||
|
||||
return etag(buf, {weak: true})
|
||||
return etag(buf, {weak: true});
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -120,18 +122,8 @@ exports.normalizeTypes = function(types){
|
||||
* @api private
|
||||
*/
|
||||
|
||||
exports.contentDisposition = function(filename){
|
||||
var ret = 'attachment';
|
||||
if (filename) {
|
||||
filename = basename(filename);
|
||||
// if filename contains non-ascii characters, add a utf-8 version ala RFC 5987
|
||||
ret = /[^\040-\176]/.test(filename)
|
||||
? 'attachment; filename="' + encodeURI(filename) + '"; filename*=UTF-8\'\'' + encodeURI(filename)
|
||||
: 'attachment; filename="' + filename + '"';
|
||||
}
|
||||
|
||||
return ret;
|
||||
};
|
||||
exports.contentDisposition = deprecate.function(contentDisposition,
|
||||
'utils.contentDisposition: use content-disposition npm module instead');
|
||||
|
||||
/**
|
||||
* Parse accept params `str` returning an
|
||||
|
||||
89
lib/view.js
89
lib/view.js
@@ -2,14 +2,21 @@
|
||||
* Module dependencies.
|
||||
*/
|
||||
|
||||
var debug = require('debug')('express:view');
|
||||
var path = require('path');
|
||||
var fs = require('fs');
|
||||
var utils = require('./utils');
|
||||
|
||||
/**
|
||||
* Module variables.
|
||||
* @private
|
||||
*/
|
||||
|
||||
var dirname = path.dirname;
|
||||
var basename = path.basename;
|
||||
var extname = path.extname;
|
||||
var exists = fs.existsSync || path.existsSync;
|
||||
var join = path.join;
|
||||
var resolve = path.resolve;
|
||||
|
||||
/**
|
||||
* Expose `View`.
|
||||
@@ -45,23 +52,32 @@ function View(name, options) {
|
||||
}
|
||||
|
||||
/**
|
||||
* Lookup view by the given `path`
|
||||
* Lookup view by the given `name`
|
||||
*
|
||||
* @param {String} path
|
||||
* @param {String} name
|
||||
* @return {String}
|
||||
* @api private
|
||||
*/
|
||||
|
||||
View.prototype.lookup = function(path){
|
||||
var ext = this.ext;
|
||||
View.prototype.lookup = function lookup(name) {
|
||||
var path;
|
||||
var roots = [].concat(this.root);
|
||||
|
||||
// <path>.<engine>
|
||||
if (!utils.isAbsolute(path)) path = join(this.root, path);
|
||||
if (exists(path)) return path;
|
||||
debug('lookup "%s"', name);
|
||||
|
||||
// <path>/index.<engine>
|
||||
path = join(dirname(path), basename(path, ext), 'index' + ext);
|
||||
if (exists(path)) return path;
|
||||
for (var i = 0; i < roots.length && !path; i++) {
|
||||
var root = roots[i];
|
||||
|
||||
// resolve the path
|
||||
var loc = resolve(root, name);
|
||||
var dir = dirname(loc);
|
||||
var file = basename(loc);
|
||||
|
||||
// resolve the file
|
||||
path = this.resolve(dir, file);
|
||||
}
|
||||
|
||||
return path;
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -72,6 +88,55 @@ View.prototype.lookup = function(path){
|
||||
* @api private
|
||||
*/
|
||||
|
||||
View.prototype.render = function(options, fn){
|
||||
View.prototype.render = function render(options, fn) {
|
||||
debug('render "%s"', this.path);
|
||||
this.engine(this.path, options, fn);
|
||||
};
|
||||
|
||||
/**
|
||||
* Resolve the file within the given directory.
|
||||
*
|
||||
* @param {string} dir
|
||||
* @param {string} file
|
||||
* @private
|
||||
*/
|
||||
|
||||
View.prototype.resolve = function resolve(dir, file) {
|
||||
var ext = this.ext;
|
||||
var path;
|
||||
var stat;
|
||||
|
||||
// <path>.<ext>
|
||||
path = join(dir, file);
|
||||
stat = tryStat(path);
|
||||
|
||||
if (stat && stat.isFile()) {
|
||||
return path;
|
||||
}
|
||||
|
||||
// <path>/index.<ext>
|
||||
path = join(dir, basename(file, ext), 'index' + ext);
|
||||
stat = tryStat(path);
|
||||
|
||||
if (stat && stat.isFile()) {
|
||||
return path;
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Return a stat, maybe.
|
||||
*
|
||||
* @param {string} path
|
||||
* @return {fs.Stats}
|
||||
* @private
|
||||
*/
|
||||
|
||||
function tryStat(path) {
|
||||
debug('stat "%s"', path);
|
||||
|
||||
try {
|
||||
return fs.statSync(path);
|
||||
} catch (e) {
|
||||
return undefined;
|
||||
}
|
||||
}
|
||||
|
||||
57
package.json
57
package.json
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"name": "express",
|
||||
"description": "Fast, unopinionated, minimalist web framework",
|
||||
"version": "4.9.8",
|
||||
"version": "4.10.5",
|
||||
"author": "TJ Holowaychuk <tj@vision-media.ca>",
|
||||
"contributors": [
|
||||
"Aaron Heckmann <aaron.heckmann+github@gmail.com>",
|
||||
@@ -12,6 +12,9 @@
|
||||
"Roman Shtylman <shtylman+expressjs@gmail.com>",
|
||||
"Young Jae Sim <hanul@hanul.me>"
|
||||
],
|
||||
"license": "MIT",
|
||||
"repository": "strongloop/express",
|
||||
"homepage": "http://expressjs.com/",
|
||||
"keywords": [
|
||||
"express",
|
||||
"framework",
|
||||
@@ -23,29 +26,27 @@
|
||||
"app",
|
||||
"api"
|
||||
],
|
||||
"repository": "strongloop/express",
|
||||
"license": "MIT",
|
||||
"homepage": "http://expressjs.com/",
|
||||
"dependencies": {
|
||||
"accepts": "~1.1.2",
|
||||
"accepts": "~1.1.4",
|
||||
"content-disposition": "0.5.0",
|
||||
"cookie-signature": "1.0.5",
|
||||
"debug": "~2.0.0",
|
||||
"depd": "0.4.5",
|
||||
"debug": "~2.1.0",
|
||||
"depd": "~1.0.0",
|
||||
"escape-html": "1.0.1",
|
||||
"etag": "~1.4.0",
|
||||
"finalhandler": "0.2.0",
|
||||
"etag": "~1.5.1",
|
||||
"finalhandler": "0.3.2",
|
||||
"fresh": "0.2.4",
|
||||
"media-typer": "0.3.0",
|
||||
"methods": "1.1.0",
|
||||
"on-finished": "~2.1.0",
|
||||
"on-finished": "~2.1.1",
|
||||
"parseurl": "~1.3.0",
|
||||
"path-to-regexp": "0.1.3",
|
||||
"proxy-addr": "~1.0.3",
|
||||
"qs": "2.2.4",
|
||||
"proxy-addr": "~1.0.4",
|
||||
"qs": "2.3.3",
|
||||
"range-parser": "~1.0.2",
|
||||
"send": "0.9.3",
|
||||
"serve-static": "~1.6.4",
|
||||
"type-is": "~1.5.2",
|
||||
"send": "0.10.1",
|
||||
"serve-static": "~1.7.1",
|
||||
"type-is": "~1.5.4",
|
||||
"vary": "~1.0.0",
|
||||
"cookie": "0.1.2",
|
||||
"merge-descriptors": "0.0.2",
|
||||
@@ -54,27 +55,33 @@
|
||||
"devDependencies": {
|
||||
"after": "0.8.1",
|
||||
"istanbul": "0.3.2",
|
||||
"mocha": "~1.21.5",
|
||||
"should": "~4.0.4",
|
||||
"supertest": "~0.14.0",
|
||||
"mocha": "~2.0.0",
|
||||
"should": "~4.3.0",
|
||||
"supertest": "~0.15.0",
|
||||
"ejs": "~1.0.0",
|
||||
"marked": "0.3.2",
|
||||
"hjs": "~0.0.6",
|
||||
"body-parser": "~1.8.2",
|
||||
"body-parser": "~1.9.3",
|
||||
"connect-redis": "~2.1.0",
|
||||
"cookie-parser": "~1.3.3",
|
||||
"express-session": "~1.8.2",
|
||||
"jade": "~1.6.0",
|
||||
"method-override": "~2.2.0",
|
||||
"morgan": "~1.3.1",
|
||||
"multiparty": "~3.3.2",
|
||||
"express-session": "~1.9.2",
|
||||
"jade": "~1.7.0",
|
||||
"method-override": "~2.3.0",
|
||||
"morgan": "~1.5.0",
|
||||
"multiparty": "~4.0.0",
|
||||
"vhost": "~3.0.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 0.10.0"
|
||||
},
|
||||
"files": [
|
||||
"LICENSE",
|
||||
"History.md",
|
||||
"Readme.md",
|
||||
"index.js",
|
||||
"lib/"
|
||||
],
|
||||
"scripts": {
|
||||
"prepublish": "npm prune",
|
||||
"test": "mocha --require test/support/env --reporter spec --bail --check-leaks test/ test/acceptance/",
|
||||
"test-cov": "istanbul cover node_modules/mocha/bin/_mocha -- --require test/support/env --reporter dot --check-leaks test/ test/acceptance/",
|
||||
"test-tap": "mocha --require test/support/env --reporter tap --check-leaks test/ test/acceptance/",
|
||||
|
||||
@@ -43,6 +43,16 @@ describe('Router', function(){
|
||||
router.handle({ url: '/test/route', method: 'GET' }, { end: done });
|
||||
});
|
||||
|
||||
it('should handle blank URL', function(done){
|
||||
var router = new Router();
|
||||
|
||||
router.use(function (req, res) {
|
||||
false.should.be.true;
|
||||
});
|
||||
|
||||
router.handle({ url: '', method: 'GET' }, {}, done);
|
||||
});
|
||||
|
||||
describe('.handle', function(){
|
||||
it('should dispatch', function(done){
|
||||
var router = new Router();
|
||||
@@ -209,6 +219,23 @@ describe('Router', function(){
|
||||
});
|
||||
});
|
||||
|
||||
it('should ignore FQDN in path', function (done) {
|
||||
var request = { hit: 0, url: '/proxy/http://example.com/blog/post/1', method: 'GET' };
|
||||
var router = new Router();
|
||||
|
||||
router.use('/proxy', function (req, res, next) {
|
||||
assert.equal(req.hit++, 0);
|
||||
assert.equal(req.url, '/http://example.com/blog/post/1');
|
||||
next();
|
||||
});
|
||||
|
||||
router.handle(request, {}, function (err) {
|
||||
if (err) return done(err);
|
||||
assert.equal(request.hit, 1);
|
||||
done();
|
||||
});
|
||||
});
|
||||
|
||||
it('should adjust FQDN req.url', function (done) {
|
||||
var request = { hit: 0, url: 'http://example.com/blog/post/1', method: 'GET' };
|
||||
var router = new Router();
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
var app = require('../../examples/auth/app')
|
||||
var app = require('../../examples/auth')
|
||||
var request = require('supertest')
|
||||
|
||||
function getCookie(res) {
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
|
||||
var app = require('../../examples/cookies/app')
|
||||
var app = require('../../examples/cookies')
|
||||
, request = require('supertest');
|
||||
|
||||
describe('cookies', function(){
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
|
||||
var app = require('../../examples/downloads/app')
|
||||
var app = require('../../examples/downloads')
|
||||
, request = require('supertest');
|
||||
|
||||
describe('downloads', function(){
|
||||
|
||||
44
test/acceptance/multi-router.js
Normal file
44
test/acceptance/multi-router.js
Normal file
@@ -0,0 +1,44 @@
|
||||
var app = require('../../examples/multi-router')
|
||||
var request = require('supertest')
|
||||
|
||||
describe('multi-router', function(){
|
||||
describe('GET /',function(){
|
||||
it('should respond with root handler', function(done){
|
||||
request(app)
|
||||
.get('/')
|
||||
.expect(200, 'Hello form root route.', done)
|
||||
})
|
||||
})
|
||||
|
||||
describe('GET /api/v1/',function(){
|
||||
it('should respond with APIv1 root handler', function(done){
|
||||
request(app)
|
||||
.get('/api/v1/')
|
||||
.expect(200, 'Hello from APIv1 root route.', done)
|
||||
})
|
||||
})
|
||||
|
||||
describe('GET /api/v1/users',function(){
|
||||
it('should respond with users from APIv1', function(done){
|
||||
request(app)
|
||||
.get('/api/v1/users')
|
||||
.expect(200, 'List of APIv1 users.', done)
|
||||
})
|
||||
})
|
||||
|
||||
describe('GET /api/v2/',function(){
|
||||
it('should respond with APIv2 root handler', function(done){
|
||||
request(app)
|
||||
.get('/api/v2/')
|
||||
.expect(200, 'Hello from APIv2 root route.', done)
|
||||
})
|
||||
})
|
||||
|
||||
describe('GET /api/v2/users',function(){
|
||||
it('should respond with users from APIv2', function(done){
|
||||
request(app)
|
||||
.get('/api/v2/users')
|
||||
.expect(200, 'List of APIv2 users.', done)
|
||||
})
|
||||
})
|
||||
})
|
||||
@@ -1,4 +1,4 @@
|
||||
var app = require('../../examples/params/app')
|
||||
var app = require('../../examples/params')
|
||||
var request = require('supertest')
|
||||
|
||||
describe('params', function(){
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
var app = require('../../examples/resource/app')
|
||||
var app = require('../../examples/resource')
|
||||
var request = require('supertest')
|
||||
|
||||
describe('resource', function(){
|
||||
|
||||
@@ -131,6 +131,64 @@ describe('app', function(){
|
||||
})
|
||||
})
|
||||
|
||||
describe('when "views" is given', function(){
|
||||
it('should lookup the file in the path', function(done){
|
||||
var app = express();
|
||||
|
||||
app.set('views', __dirname + '/fixtures/default_layout');
|
||||
app.locals.user = { name: 'tobi' };
|
||||
|
||||
app.render('user.jade', function(err, str){
|
||||
if (err) return done(err);
|
||||
str.should.equal('<p>tobi</p>');
|
||||
done();
|
||||
})
|
||||
})
|
||||
|
||||
describe('when array of paths', function(){
|
||||
it('should lookup the file in the path', function(done){
|
||||
var app = express();
|
||||
var views = [__dirname + '/fixtures/local_layout', __dirname + '/fixtures/default_layout'];
|
||||
|
||||
app.set('views', views);
|
||||
app.locals.user = { name: 'tobi' };
|
||||
|
||||
app.render('user.jade', function(err, str){
|
||||
if (err) return done(err);
|
||||
str.should.equal('<span>tobi</span>');
|
||||
done();
|
||||
})
|
||||
})
|
||||
|
||||
it('should lookup in later paths until found', function(done){
|
||||
var app = express();
|
||||
var views = [__dirname + '/fixtures/local_layout', __dirname + '/fixtures/default_layout'];
|
||||
|
||||
app.set('views', views);
|
||||
app.locals.name = 'tobi';
|
||||
|
||||
app.render('name.jade', function(err, str){
|
||||
if (err) return done(err);
|
||||
str.should.equal('<p>tobi</p>');
|
||||
done();
|
||||
})
|
||||
})
|
||||
|
||||
it('should error if file does not exist', function(done){
|
||||
var app = express();
|
||||
var views = [__dirname + '/fixtures/local_layout', __dirname + '/fixtures/default_layout'];
|
||||
|
||||
app.set('views', views);
|
||||
app.locals.name = 'tobi';
|
||||
|
||||
app.render('pet.jade', function(err, str){
|
||||
err.message.should.equal('Failed to lookup view "pet.jade" in views directories "' + __dirname + '/fixtures/local_layout" or "' + __dirname + '/fixtures/default_layout"');
|
||||
done();
|
||||
})
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
describe('when a "view" constructor is given', function(){
|
||||
it('should create an instance of it', function(done){
|
||||
var app = express();
|
||||
|
||||
1
test/fixtures/default_layout/name.jade
vendored
Normal file
1
test/fixtures/default_layout/name.jade
vendored
Normal file
@@ -0,0 +1 @@
|
||||
p= name
|
||||
1
test/fixtures/default_layout/user.jade
vendored
Normal file
1
test/fixtures/default_layout/user.jade
vendored
Normal file
@@ -0,0 +1 @@
|
||||
p= user.name
|
||||
1
test/fixtures/local_layout/user.jade
vendored
Normal file
1
test/fixtures/local_layout/user.jade
vendored
Normal file
@@ -0,0 +1 @@
|
||||
span= user.name
|
||||
@@ -56,10 +56,8 @@ describe('res', function(){
|
||||
|
||||
request(app)
|
||||
.get('/')
|
||||
.expect('Content-Disposition', 'attachment;' +
|
||||
' filename="%E6%97%A5%E6%9C%AC%E8%AA%9E.txt";' +
|
||||
' filename*=UTF-8\'\'%E6%97%A5%E6%9C%AC%E8%AA%9E.txt',
|
||||
done);
|
||||
.expect('Content-Disposition', 'attachment; filename="???.txt"; filename*=UTF-8\'\'%E6%97%A5%E6%9C%AC%E8%AA%9E.txt')
|
||||
.expect(200, done);
|
||||
})
|
||||
|
||||
it('should set the Content-Type', function(done){
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
|
||||
var express = require('../')
|
||||
, request = require('supertest')
|
||||
, mixin = require('utils-merge')
|
||||
, cookie = require('cookie')
|
||||
, cookieParser = require('cookie-parser')
|
||||
var merge = require('utils-merge');
|
||||
|
||||
describe('res', function(){
|
||||
describe('.cookie(name, object)', function(){
|
||||
@@ -113,7 +113,7 @@ describe('res', function(){
|
||||
var app = express();
|
||||
|
||||
var options = { maxAge: 1000 };
|
||||
var optionsCopy = mixin({}, options);
|
||||
var optionsCopy = merge({}, options);
|
||||
|
||||
app.use(function(req, res){
|
||||
res.cookie('name', 'tobi', options)
|
||||
|
||||
@@ -114,6 +114,54 @@ describe('res', function(){
|
||||
.expect('<p>This is an email</p>', done);
|
||||
})
|
||||
})
|
||||
|
||||
describe('when "views" is given', function(){
|
||||
it('should lookup the file in the path', function(done){
|
||||
var app = express();
|
||||
|
||||
app.set('views', __dirname + '/fixtures/default_layout');
|
||||
|
||||
app.use(function(req, res){
|
||||
res.render('user.jade', { user: { name: 'tobi' } });
|
||||
});
|
||||
|
||||
request(app)
|
||||
.get('/')
|
||||
.expect('<p>tobi</p>', done);
|
||||
})
|
||||
|
||||
describe('when array of paths', function(){
|
||||
it('should lookup the file in the path', function(done){
|
||||
var app = express();
|
||||
var views = [__dirname + '/fixtures/local_layout', __dirname + '/fixtures/default_layout'];
|
||||
|
||||
app.set('views', views);
|
||||
|
||||
app.use(function(req, res){
|
||||
res.render('user.jade', { user: { name: 'tobi' } });
|
||||
});
|
||||
|
||||
request(app)
|
||||
.get('/')
|
||||
.expect('<span>tobi</span>', done);
|
||||
})
|
||||
|
||||
it('should lookup in later paths until found', function(done){
|
||||
var app = express();
|
||||
var views = [__dirname + '/fixtures/local_layout', __dirname + '/fixtures/default_layout'];
|
||||
|
||||
app.set('views', views);
|
||||
|
||||
app.use(function(req, res){
|
||||
res.render('name.jade', { name: 'tobi' });
|
||||
});
|
||||
|
||||
request(app)
|
||||
.get('/')
|
||||
.expect('<p>tobi</p>', done);
|
||||
})
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
describe('.render(name, option)', function(){
|
||||
|
||||
@@ -69,6 +69,27 @@ describe('res', function(){
|
||||
.end(done);
|
||||
})
|
||||
|
||||
it('should not error if the client aborts', function (done) {
|
||||
var cb = after(1, done);
|
||||
var app = express();
|
||||
|
||||
app.use(function (req, res) {
|
||||
setImmediate(function () {
|
||||
res.sendFile(path.resolve(fixtures, 'name.txt'));
|
||||
cb();
|
||||
});
|
||||
test.abort();
|
||||
});
|
||||
|
||||
app.use(function (err, req, res, next) {
|
||||
err.code.should.be.empty;
|
||||
cb();
|
||||
});
|
||||
|
||||
var test = request(app).get('/');
|
||||
test.expect(200, cb);
|
||||
})
|
||||
|
||||
describe('with "dotfiles" option', function () {
|
||||
it('should not serve dotfiles by default', function (done) {
|
||||
var app = createApp(path.resolve(__dirname, 'fixtures/.name'));
|
||||
@@ -455,6 +476,27 @@ describe('res', function(){
|
||||
.expect(200, '20%', done);
|
||||
});
|
||||
|
||||
it('should not error if the client aborts', function (done) {
|
||||
var cb = after(1, done);
|
||||
var app = express();
|
||||
|
||||
app.use(function (req, res) {
|
||||
setImmediate(function () {
|
||||
res.sendfile(path.resolve(fixtures, 'name.txt'));
|
||||
cb();
|
||||
});
|
||||
test.abort();
|
||||
});
|
||||
|
||||
app.use(function (err, req, res, next) {
|
||||
err.code.should.be.empty;
|
||||
cb();
|
||||
});
|
||||
|
||||
var test = request(app).get('/');
|
||||
test.expect(200, cb);
|
||||
})
|
||||
|
||||
describe('with an absolute path', function(){
|
||||
it('should transfer the file', function(done){
|
||||
var app = express();
|
||||
|
||||
Reference in New Issue
Block a user