Bring up the oracle integration
This commit is contained in:
parent
8870323980
commit
d856ca026d
|
@ -1,4 +1,5 @@
|
|||
|
||||
.idea
|
||||
.project
|
||||
.DS_Store
|
||||
*.seed
|
||||
*.log
|
||||
|
@ -10,9 +11,10 @@
|
|||
*.swo
|
||||
/node_modules/*/node_modules
|
||||
/node_modules/debug
|
||||
/node_modules/jugglingdb
|
||||
/node_modules/express
|
||||
/node_modules/jugglingdb*
|
||||
/node_modules/mocha
|
||||
/node_modules/sl-module-loader
|
||||
/node_modules/sl-remoting
|
||||
/node_modules/merge
|
||||
/node_modules/inflection
|
||||
/node_modules/inflection
|
||||
|
|
|
@ -0,0 +1,32 @@
|
|||
var asteroid = require('../../');
|
||||
var app = asteroid();
|
||||
|
||||
app.use(asteroid.rest());
|
||||
|
||||
|
||||
var dataSource = app.dataSource('db',
|
||||
{ adapter: 'oracle',
|
||||
host: '166.78.158.45',
|
||||
database: 'XE',
|
||||
username: 'strongloop',
|
||||
password: 'str0ng100pjs',
|
||||
debug: true
|
||||
});
|
||||
|
||||
|
||||
var Color = dataSource.define('color', {
|
||||
'name': String
|
||||
});
|
||||
dataSource.autoupdate(function (err, data) {
|
||||
Color.create({name: 'red'});
|
||||
Color.create({name: 'green'});
|
||||
Color.create({name: 'blue'});
|
||||
|
||||
Color.all(function () {
|
||||
console.log(arguments);
|
||||
});
|
||||
});
|
||||
|
||||
app.listen(3000);
|
||||
|
||||
console.log('a list of colors is available at http://localhost:300/colors');
|
|
@ -4,7 +4,7 @@
|
|||
|
||||
var Model = require('../node_modules/model/lib/model')
|
||||
, DataSource = require('jugglingdb').DataSource
|
||||
, ADL = require('jugglingdb').ADL
|
||||
, ModelBuilder = require('jugglingdb').ModelBuilder
|
||||
, assert = require('assert')
|
||||
, RemoteObjects = require('sl-remoting')
|
||||
, i8n = require('inflection');
|
||||
|
@ -48,11 +48,11 @@ app.disuse = function (route) {
|
|||
app.models = {};
|
||||
|
||||
/**
|
||||
* Get ADL.
|
||||
* Get ModelBuilder.
|
||||
*/
|
||||
|
||||
app.adl = function () {
|
||||
return this._adl || (this._adl = new ADL())
|
||||
app.modelBuilder = function () {
|
||||
return this.modelBuilder || (this._modelBuilder = new ModelBuilder())
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -66,9 +66,9 @@ app.adl = function () {
|
|||
app.model =
|
||||
app.defineModel =
|
||||
app.define = function (name, properties, options) {
|
||||
var adl = this.adl();
|
||||
var modelBuilder = this.modelBuilder();
|
||||
|
||||
var ModelCtor = adl.define(name, properties, options);
|
||||
var ModelCtor = modelBuilder.define(name, properties, options);
|
||||
|
||||
ModelCtor.dataSource = function (name) {
|
||||
var dataSource = app.dataSources[name];
|
||||
|
|
|
@ -1,9 +0,0 @@
|
|||
.git*
|
||||
docs/
|
||||
examples/
|
||||
support/
|
||||
test/
|
||||
testing.js
|
||||
.DS_Store
|
||||
coverage.html
|
||||
lib-cov
|
|
@ -1,4 +0,0 @@
|
|||
language: node_js
|
||||
node_js:
|
||||
- "0.8"
|
||||
- "0.10"
|
File diff suppressed because it is too large
Load Diff
|
@ -1,22 +0,0 @@
|
|||
(The MIT License)
|
||||
|
||||
Copyright (c) 2009-2011 TJ Holowaychuk <tj@vision-media.ca>
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining
|
||||
a copy of this software and associated documentation files (the
|
||||
'Software'), to deal in the Software without restriction, including
|
||||
without limitation the rights to use, copy, modify, merge, publish,
|
||||
distribute, sublicense, and/or sell copies of the Software, and to
|
||||
permit persons to whom the Software is furnished to do so, subject to
|
||||
the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be
|
||||
included in all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND,
|
||||
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
||||
IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
|
||||
CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
|
||||
TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
|
||||
SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
|
@ -1,33 +0,0 @@
|
|||
|
||||
MOCHA_OPTS= --check-leaks
|
||||
REPORTER = dot
|
||||
|
||||
check: test
|
||||
|
||||
test: test-unit test-acceptance
|
||||
|
||||
test-unit:
|
||||
@NODE_ENV=test ./node_modules/.bin/mocha \
|
||||
--reporter $(REPORTER) \
|
||||
$(MOCHA_OPTS)
|
||||
|
||||
test-acceptance:
|
||||
@NODE_ENV=test ./node_modules/.bin/mocha \
|
||||
--reporter $(REPORTER) \
|
||||
--bail \
|
||||
test/acceptance/*.js
|
||||
|
||||
test-cov: lib-cov
|
||||
@EXPRESS_COV=1 $(MAKE) test REPORTER=html-cov > coverage.html
|
||||
|
||||
lib-cov:
|
||||
@jscoverage lib lib-cov
|
||||
|
||||
benchmark:
|
||||
@./support/bench
|
||||
|
||||
clean:
|
||||
rm -f coverage.html
|
||||
rm -fr lib-cov
|
||||
|
||||
.PHONY: test test-unit test-acceptance benchmark clean
|
|
@ -1,180 +0,0 @@
|
|||
![express logo](http://f.cl.ly/items/0V2S1n0K1i3y1c122g04/Screen%20Shot%202012-04-11%20at%209.59.42%20AM.png)
|
||||
|
||||
Fast, unopinionated, minimalist web framework for [node](http://nodejs.org). [![Build Status](https://secure.travis-ci.org/visionmedia/express.png)](http://travis-ci.org/visionmedia/express) [![Dependency Status](https://gemnasium.com/visionmedia/express.png)](https://gemnasium.com/visionmedia/express)
|
||||
|
||||
```js
|
||||
var express = require('express');
|
||||
var app = express();
|
||||
|
||||
app.get('/', function(req, res){
|
||||
res.send('Hello World');
|
||||
});
|
||||
|
||||
app.listen(3000);
|
||||
```
|
||||
|
||||
## Installation
|
||||
|
||||
$ npm install -g express
|
||||
|
||||
## Quick Start
|
||||
|
||||
The quickest way to get started with express is to utilize the executable `express(1)` to generate an application as shown below:
|
||||
|
||||
Create the app:
|
||||
|
||||
$ npm install -g express
|
||||
$ express /tmp/foo && cd /tmp/foo
|
||||
|
||||
Install dependencies:
|
||||
|
||||
$ npm install
|
||||
|
||||
Start the server:
|
||||
|
||||
$ node app
|
||||
|
||||
## Features
|
||||
|
||||
* Built on [Connect](http://github.com/senchalabs/connect)
|
||||
* Robust routing
|
||||
* HTTP helpers (redirection, caching, etc)
|
||||
* View system supporting 14+ template engines
|
||||
* Content negotiation
|
||||
* Focus on high performance
|
||||
* Environment based configuration
|
||||
* Executable for generating applications quickly
|
||||
* High test coverage
|
||||
|
||||
## Philosophy
|
||||
|
||||
The Express philosophy is to provide small, robust tooling for HTTP servers. Making
|
||||
it a great solution for single page applications, web sites, hybrids, or public
|
||||
HTTP APIs.
|
||||
|
||||
Built on Connect you can use _only_ what you need, and nothing more, applications
|
||||
can be as big or as small as you like, even a single file. Express does
|
||||
not force you to use any specific ORM or template engine. With support for over
|
||||
14 template engines via [Consolidate.js](http://github.com/visionmedia/consolidate.js)
|
||||
you can quickly craft your perfect framework.
|
||||
|
||||
## More Information
|
||||
|
||||
* Join #express on freenode
|
||||
* [Google Group](http://groups.google.com/group/express-js) for discussion
|
||||
* Follow [tjholowaychuk](http://twitter.com/tjholowaychuk) on twitter for updates
|
||||
* Visit the [Wiki](http://github.com/visionmedia/express/wiki)
|
||||
* [日本語ドキュメンテーション](http://hideyukisaito.com/doc/expressjs/) by [hideyukisaito](https://github.com/hideyukisaito)
|
||||
* [Русскоязычная документация](http://jsman.ru/express/)
|
||||
* Run express examples [online](https://runnable.com/express)
|
||||
|
||||
## Viewing Examples
|
||||
|
||||
Clone the Express repo, then install the dev dependencies to install all the example / test suite deps:
|
||||
|
||||
$ git clone git://github.com/visionmedia/express.git --depth 1
|
||||
$ cd express
|
||||
$ npm install
|
||||
|
||||
then run whichever tests you want:
|
||||
|
||||
$ node examples/content-negotiation
|
||||
|
||||
## 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
|
||||
|
||||
## Contributors
|
||||
|
||||
```
|
||||
project: express
|
||||
commits: 3559
|
||||
active : 468 days
|
||||
files : 237
|
||||
authors:
|
||||
1891 Tj Holowaychuk 53.1%
|
||||
1285 visionmedia 36.1%
|
||||
182 TJ Holowaychuk 5.1%
|
||||
54 Aaron Heckmann 1.5%
|
||||
34 csausdev 1.0%
|
||||
26 ciaranj 0.7%
|
||||
21 Robert Sköld 0.6%
|
||||
6 Guillermo Rauch 0.2%
|
||||
3 Dav Glass 0.1%
|
||||
3 Nick Poulden 0.1%
|
||||
2 Randy Merrill 0.1%
|
||||
2 Benny Wong 0.1%
|
||||
2 Hunter Loftis 0.1%
|
||||
2 Jake Gordon 0.1%
|
||||
2 Brian McKinney 0.1%
|
||||
2 Roman Shtylman 0.1%
|
||||
2 Ben Weaver 0.1%
|
||||
2 Dave Hoover 0.1%
|
||||
2 Eivind Fjeldstad 0.1%
|
||||
2 Daniel Shaw 0.1%
|
||||
1 Matt Colyer 0.0%
|
||||
1 Pau Ramon 0.0%
|
||||
1 Pero Pejovic 0.0%
|
||||
1 Peter Rekdal Sunde 0.0%
|
||||
1 Raynos 0.0%
|
||||
1 Teng Siong Ong 0.0%
|
||||
1 Viktor Kelemen 0.0%
|
||||
1 ctide 0.0%
|
||||
1 8bitDesigner 0.0%
|
||||
1 isaacs 0.0%
|
||||
1 mgutz 0.0%
|
||||
1 pikeas 0.0%
|
||||
1 shuwatto 0.0%
|
||||
1 tstrimple 0.0%
|
||||
1 ewoudj 0.0%
|
||||
1 Adam Sanderson 0.0%
|
||||
1 Andrii Kostenko 0.0%
|
||||
1 Andy Hiew 0.0%
|
||||
1 Arpad Borsos 0.0%
|
||||
1 Ashwin Purohit 0.0%
|
||||
1 Benjen 0.0%
|
||||
1 Darren Torpey 0.0%
|
||||
1 Greg Ritter 0.0%
|
||||
1 Gregory Ritter 0.0%
|
||||
1 James Herdman 0.0%
|
||||
1 Jim Snodgrass 0.0%
|
||||
1 Joe McCann 0.0%
|
||||
1 Jonathan Dumaine 0.0%
|
||||
1 Jonathan Palardy 0.0%
|
||||
1 Jonathan Zacsh 0.0%
|
||||
1 Justin Lilly 0.0%
|
||||
1 Ken Sato 0.0%
|
||||
1 Maciej Małecki 0.0%
|
||||
1 Masahiro Hayashi 0.0%
|
||||
```
|
||||
|
||||
## License
|
||||
|
||||
(The MIT License)
|
||||
|
||||
Copyright (c) 2009-2012 TJ Holowaychuk <tj@vision-media.ca>
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining
|
||||
a copy of this software and associated documentation files (the
|
||||
'Software'), to deal in the Software without restriction, including
|
||||
without limitation the rights to use, copy, modify, merge, publish,
|
||||
distribute, sublicense, and/or sell copies of the Software, and to
|
||||
permit persons to whom the Software is furnished to do so, subject to
|
||||
the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be
|
||||
included in all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND,
|
||||
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
||||
IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
|
||||
CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
|
||||
TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
|
||||
SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
|
@ -1,422 +0,0 @@
|
|||
#!/usr/bin/env node
|
||||
|
||||
/**
|
||||
* Module dependencies.
|
||||
*/
|
||||
|
||||
var exec = require('child_process').exec
|
||||
, program = require('commander')
|
||||
, mkdirp = require('mkdirp')
|
||||
, pkg = require('../package.json')
|
||||
, version = pkg.version
|
||||
, os = require('os')
|
||||
, fs = require('fs');
|
||||
|
||||
// CLI
|
||||
|
||||
program
|
||||
.version(version)
|
||||
.option('-s, --sessions', 'add session support')
|
||||
.option('-e, --ejs', 'add ejs engine support (defaults to jade)')
|
||||
.option('-J, --jshtml', 'add jshtml engine support (defaults to jade)')
|
||||
.option('-H, --hogan', 'add hogan.js engine support')
|
||||
.option('-c, --css <engine>', 'add stylesheet <engine> support (less|stylus) (defaults to plain css)')
|
||||
.option('-f, --force', 'force on non-empty directory')
|
||||
.parse(process.argv);
|
||||
|
||||
// Path
|
||||
|
||||
var path = program.args.shift() || '.';
|
||||
|
||||
// end-of-line code
|
||||
|
||||
var eol = os.EOL
|
||||
|
||||
// Template engine
|
||||
|
||||
program.template = 'jade';
|
||||
if (program.ejs) program.template = 'ejs';
|
||||
if (program.jshtml) program.template = 'jshtml';
|
||||
if (program.hogan) program.template = 'hjs';
|
||||
|
||||
/**
|
||||
* Routes index template.
|
||||
*/
|
||||
|
||||
var index = [
|
||||
''
|
||||
, '/*'
|
||||
, ' * GET home page.'
|
||||
, ' */'
|
||||
, ''
|
||||
, 'exports.index = function(req, res){'
|
||||
, ' res.render(\'index\', { title: \'Express\' });'
|
||||
, '};'
|
||||
].join(eol);
|
||||
|
||||
/**
|
||||
* Routes users template.
|
||||
*/
|
||||
|
||||
var users = [
|
||||
''
|
||||
, '/*'
|
||||
, ' * GET users listing.'
|
||||
, ' */'
|
||||
, ''
|
||||
, 'exports.list = function(req, res){'
|
||||
, ' res.send("respond with a resource");'
|
||||
, '};'
|
||||
].join(eol);
|
||||
|
||||
/**
|
||||
* Jade layout template.
|
||||
*/
|
||||
|
||||
var jadeLayout = [
|
||||
'doctype 5'
|
||||
, 'html'
|
||||
, ' head'
|
||||
, ' title= title'
|
||||
, ' link(rel=\'stylesheet\', href=\'/stylesheets/style.css\')'
|
||||
, ' body'
|
||||
, ' block content'
|
||||
].join(eol);
|
||||
|
||||
/**
|
||||
* Jade index template.
|
||||
*/
|
||||
|
||||
var jadeIndex = [
|
||||
'extends layout'
|
||||
, ''
|
||||
, 'block content'
|
||||
, ' h1= title'
|
||||
, ' p Welcome to #{title}'
|
||||
].join(eol);
|
||||
|
||||
/**
|
||||
* EJS index template.
|
||||
*/
|
||||
|
||||
var ejsIndex = [
|
||||
'<!DOCTYPE html>'
|
||||
, '<html>'
|
||||
, ' <head>'
|
||||
, ' <title><%= title %></title>'
|
||||
, ' <link rel=\'stylesheet\' href=\'/stylesheets/style.css\' />'
|
||||
, ' </head>'
|
||||
, ' <body>'
|
||||
, ' <h1><%= title %></h1>'
|
||||
, ' <p>Welcome to <%= title %></p>'
|
||||
, ' </body>'
|
||||
, '</html>'
|
||||
].join(eol);
|
||||
|
||||
/**
|
||||
* JSHTML layout template.
|
||||
*/
|
||||
|
||||
var jshtmlLayout = [
|
||||
'<!DOCTYPE html>'
|
||||
, '<html>'
|
||||
, ' <head>'
|
||||
, ' <title> @write(title) </title>'
|
||||
, ' <link rel=\'stylesheet\' href=\'/stylesheets/style.css\' />'
|
||||
, ' </head>'
|
||||
, ' <body>'
|
||||
, ' @write(body)'
|
||||
, ' </body>'
|
||||
, '</html>'
|
||||
].join(eol);
|
||||
|
||||
/**
|
||||
* JSHTML index template.
|
||||
*/
|
||||
|
||||
var jshtmlIndex = [
|
||||
'<h1>@write(title)</h1>'
|
||||
, '<p>Welcome to @write(title)</p>'
|
||||
].join(eol);
|
||||
|
||||
/**
|
||||
* Hogan.js index template.
|
||||
*/
|
||||
var hoganIndex = [
|
||||
'<!DOCTYPE html>'
|
||||
, '<html>'
|
||||
, ' <head>'
|
||||
, ' <title>{{ title }}</title>'
|
||||
, ' <link rel=\'stylesheet\' href=\'/stylesheets/style.css\' />'
|
||||
, ' </head>'
|
||||
, ' <body>'
|
||||
, ' <h1>{{ title }}</h1>'
|
||||
, ' <p>Welcome to {{ title }}</p>'
|
||||
, ' </body>'
|
||||
, '</html>'
|
||||
].join(eol);
|
||||
|
||||
/**
|
||||
* Default css template.
|
||||
*/
|
||||
|
||||
var css = [
|
||||
'body {'
|
||||
, ' padding: 50px;'
|
||||
, ' font: 14px "Lucida Grande", Helvetica, Arial, sans-serif;'
|
||||
, '}'
|
||||
, ''
|
||||
, 'a {'
|
||||
, ' color: #00B7FF;'
|
||||
, '}'
|
||||
].join(eol);
|
||||
|
||||
/**
|
||||
* Default less template.
|
||||
*/
|
||||
|
||||
var less = [
|
||||
'body {'
|
||||
, ' padding: 50px;'
|
||||
, ' font: 14px "Lucida Grande", Helvetica, Arial, sans-serif;'
|
||||
, '}'
|
||||
, ''
|
||||
, 'a {'
|
||||
, ' color: #00B7FF;'
|
||||
, '}'
|
||||
].join(eol);
|
||||
|
||||
/**
|
||||
* Default stylus template.
|
||||
*/
|
||||
|
||||
var stylus = [
|
||||
'body'
|
||||
, ' padding: 50px'
|
||||
, ' font: 14px "Lucida Grande", Helvetica, Arial, sans-serif'
|
||||
, 'a'
|
||||
, ' color: #00B7FF'
|
||||
].join(eol);
|
||||
|
||||
/**
|
||||
* App template.
|
||||
*/
|
||||
|
||||
var app = [
|
||||
''
|
||||
, '/**'
|
||||
, ' * Module dependencies.'
|
||||
, ' */'
|
||||
, ''
|
||||
, 'var express = require(\'express\')'
|
||||
, ' , routes = require(\'./routes\')'
|
||||
, ' , user = require(\'./routes/user\')'
|
||||
, ' , http = require(\'http\')'
|
||||
, ' , path = require(\'path\');'
|
||||
, ''
|
||||
, 'var app = express();'
|
||||
, ''
|
||||
, '// all environments'
|
||||
, 'app.set(\'port\', process.env.PORT || 3000);'
|
||||
, 'app.set(\'views\', __dirname + \'/views\');'
|
||||
, 'app.set(\'view engine\', \':TEMPLATE\');'
|
||||
, 'app.use(express.favicon());'
|
||||
, 'app.use(express.logger(\'dev\'));'
|
||||
, 'app.use(express.bodyParser());'
|
||||
, 'app.use(express.methodOverride());{sess}'
|
||||
, 'app.use(app.router);{css}'
|
||||
, 'app.use(express.static(path.join(__dirname, \'public\')));'
|
||||
, ''
|
||||
, '// development only'
|
||||
, 'if (\'development\' == app.get(\'env\')) {'
|
||||
, ' app.use(express.errorHandler());'
|
||||
, '}'
|
||||
, ''
|
||||
, 'app.get(\'/\', routes.index);'
|
||||
, 'app.get(\'/users\', user.list);'
|
||||
, ''
|
||||
, 'http.createServer(app).listen(app.get(\'port\'), function(){'
|
||||
, ' console.log(\'Express server listening on port \' + app.get(\'port\'));'
|
||||
, '});'
|
||||
, ''
|
||||
].join(eol);
|
||||
|
||||
// Generate application
|
||||
|
||||
(function createApplication(path) {
|
||||
emptyDirectory(path, function(empty){
|
||||
if (empty || program.force) {
|
||||
createApplicationAt(path);
|
||||
} else {
|
||||
program.confirm('destination is not empty, continue? ', function(ok){
|
||||
if (ok) {
|
||||
process.stdin.destroy();
|
||||
createApplicationAt(path);
|
||||
} else {
|
||||
abort('aborting');
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
})(path);
|
||||
|
||||
/**
|
||||
* Create application at the given directory `path`.
|
||||
*
|
||||
* @param {String} path
|
||||
*/
|
||||
|
||||
function createApplicationAt(path) {
|
||||
console.log();
|
||||
process.on('exit', function(){
|
||||
console.log();
|
||||
console.log(' install dependencies:');
|
||||
console.log(' $ cd %s && npm install', path);
|
||||
console.log();
|
||||
console.log(' run the app:');
|
||||
console.log(' $ node app');
|
||||
console.log();
|
||||
});
|
||||
|
||||
mkdir(path, function(){
|
||||
mkdir(path + '/public');
|
||||
mkdir(path + '/public/javascripts');
|
||||
mkdir(path + '/public/images');
|
||||
mkdir(path + '/public/stylesheets', function(){
|
||||
switch (program.css) {
|
||||
case 'less':
|
||||
write(path + '/public/stylesheets/style.less', less);
|
||||
break;
|
||||
case 'stylus':
|
||||
write(path + '/public/stylesheets/style.styl', stylus);
|
||||
break;
|
||||
default:
|
||||
write(path + '/public/stylesheets/style.css', css);
|
||||
}
|
||||
});
|
||||
|
||||
mkdir(path + '/routes', function(){
|
||||
write(path + '/routes/index.js', index);
|
||||
write(path + '/routes/user.js', users);
|
||||
});
|
||||
|
||||
mkdir(path + '/views', function(){
|
||||
switch (program.template) {
|
||||
case 'ejs':
|
||||
write(path + '/views/index.ejs', ejsIndex);
|
||||
break;
|
||||
case 'jade':
|
||||
write(path + '/views/layout.jade', jadeLayout);
|
||||
write(path + '/views/index.jade', jadeIndex);
|
||||
break;
|
||||
case 'jshtml':
|
||||
write(path + '/views/layout.jshtml', jshtmlLayout);
|
||||
write(path + '/views/index.jshtml', jshtmlIndex);
|
||||
break;
|
||||
case 'hjs':
|
||||
write(path + '/views/index.hjs', hoganIndex);
|
||||
break;
|
||||
|
||||
}
|
||||
});
|
||||
|
||||
// CSS Engine support
|
||||
switch (program.css) {
|
||||
case 'less':
|
||||
app = app.replace('{css}', eol + ' app.use(require(\'less-middleware\')({ src: __dirname + \'/public\' }));');
|
||||
break;
|
||||
case 'stylus':
|
||||
app = app.replace('{css}', eol + ' app.use(require(\'stylus\').middleware(__dirname + \'/public\'));');
|
||||
break;
|
||||
default:
|
||||
app = app.replace('{css}', '');
|
||||
}
|
||||
|
||||
// Session support
|
||||
app = app.replace('{sess}', program.sessions
|
||||
? eol + ' app.use(express.cookieParser(\'your secret here\'));' + eol + ' app.use(express.session());'
|
||||
: '');
|
||||
|
||||
// Template support
|
||||
app = app.replace(':TEMPLATE', program.template);
|
||||
|
||||
// package.json
|
||||
var pkg = {
|
||||
name: 'application-name'
|
||||
, version: '0.0.1'
|
||||
, private: true
|
||||
, scripts: { start: 'node app.js' }
|
||||
, dependencies: {
|
||||
express: version
|
||||
}
|
||||
}
|
||||
|
||||
if (program.template) pkg.dependencies[program.template] = '*';
|
||||
|
||||
// CSS Engine support
|
||||
switch (program.css) {
|
||||
case 'less':
|
||||
pkg.dependencies['less-middleware'] = '*';
|
||||
break;
|
||||
default:
|
||||
if (program.css) {
|
||||
pkg.dependencies[program.css] = '*';
|
||||
}
|
||||
}
|
||||
|
||||
write(path + '/package.json', JSON.stringify(pkg, null, 2));
|
||||
write(path + '/app.js', app);
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if the given directory `path` is empty.
|
||||
*
|
||||
* @param {String} path
|
||||
* @param {Function} fn
|
||||
*/
|
||||
|
||||
function emptyDirectory(path, fn) {
|
||||
fs.readdir(path, function(err, files){
|
||||
if (err && 'ENOENT' != err.code) throw err;
|
||||
fn(!files || !files.length);
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* echo str > path.
|
||||
*
|
||||
* @param {String} path
|
||||
* @param {String} str
|
||||
*/
|
||||
|
||||
function write(path, str) {
|
||||
fs.writeFile(path, str);
|
||||
console.log(' \x1b[36mcreate\x1b[0m : ' + path);
|
||||
}
|
||||
|
||||
/**
|
||||
* Mkdir -p.
|
||||
*
|
||||
* @param {String} path
|
||||
* @param {Function} fn
|
||||
*/
|
||||
|
||||
function mkdir(path, fn) {
|
||||
mkdirp(path, 0755, function(err){
|
||||
if (err) throw err;
|
||||
console.log(' \033[36mcreate\033[0m : ' + path);
|
||||
fn && fn();
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Exit with the given `str`.
|
||||
*
|
||||
* @param {String} str
|
||||
*/
|
||||
|
||||
function abort(str) {
|
||||
console.error(str);
|
||||
process.exit(1);
|
||||
}
|
|
@ -1,25 +0,0 @@
|
|||
|
||||
var http = require('http');
|
||||
|
||||
var times = 50;
|
||||
|
||||
while (times--) {
|
||||
var req = http.request({
|
||||
port: 3000
|
||||
, method: 'POST'
|
||||
, headers: { 'Content-Type': 'application/x-www-form-urlencoded' }
|
||||
});
|
||||
|
||||
req.on('response', function(res){
|
||||
console.log(res.statusCode);
|
||||
});
|
||||
|
||||
var n = 500000;
|
||||
while (n--) {
|
||||
req.write('foo=bar&bar=baz&');
|
||||
}
|
||||
|
||||
req.write('foo=bar&bar=baz');
|
||||
|
||||
req.end();
|
||||
}
|
|
@ -1,4 +0,0 @@
|
|||
|
||||
module.exports = process.env.EXPRESS_COV
|
||||
? require('./lib-cov/express')
|
||||
: require('./lib/express');
|
|
@ -1,530 +0,0 @@
|
|||
/**
|
||||
* Module dependencies.
|
||||
*/
|
||||
|
||||
var connect = require('connect')
|
||||
, Router = require('./router')
|
||||
, methods = require('methods')
|
||||
, middleware = require('./middleware')
|
||||
, debug = require('debug')('express:application')
|
||||
, locals = require('./utils').locals
|
||||
, View = require('./view')
|
||||
, utils = connect.utils
|
||||
, path = require('path')
|
||||
, http = require('http')
|
||||
, join = path.join;
|
||||
|
||||
/**
|
||||
* Application prototype.
|
||||
*/
|
||||
|
||||
var app = exports = module.exports = {};
|
||||
|
||||
/**
|
||||
* Initialize the server.
|
||||
*
|
||||
* - setup default configuration
|
||||
* - setup default middleware
|
||||
* - setup route reflection methods
|
||||
*
|
||||
* @api private
|
||||
*/
|
||||
|
||||
app.init = function(){
|
||||
this.cache = {};
|
||||
this.settings = {};
|
||||
this.engines = {};
|
||||
this.defaultConfiguration();
|
||||
};
|
||||
|
||||
/**
|
||||
* Initialize application configuration.
|
||||
*
|
||||
* @api private
|
||||
*/
|
||||
|
||||
app.defaultConfiguration = function(){
|
||||
// default settings
|
||||
this.enable('x-powered-by');
|
||||
this.set('env', process.env.NODE_ENV || 'development');
|
||||
this.set('subdomain offset', 2);
|
||||
debug('booting in %s mode', this.get('env'));
|
||||
|
||||
// implicit middleware
|
||||
this.use(connect.query());
|
||||
this.use(middleware.init(this));
|
||||
|
||||
// inherit protos
|
||||
this.on('mount', function(parent){
|
||||
this.request.__proto__ = parent.request;
|
||||
this.response.__proto__ = parent.response;
|
||||
this.engines.__proto__ = parent.engines;
|
||||
this.settings.__proto__ = parent.settings;
|
||||
});
|
||||
|
||||
// router
|
||||
this._router = new Router(this);
|
||||
this.routes = this._router.map;
|
||||
this.__defineGetter__('router', function(){
|
||||
this._usedRouter = true;
|
||||
this._router.caseSensitive = this.enabled('case sensitive routing');
|
||||
this._router.strict = this.enabled('strict routing');
|
||||
return this._router.middleware;
|
||||
});
|
||||
|
||||
// setup locals
|
||||
this.locals = locals(this);
|
||||
|
||||
// default locals
|
||||
this.locals.settings = this.settings;
|
||||
|
||||
// default configuration
|
||||
this.set('views', process.cwd() + '/views');
|
||||
this.set('jsonp callback name', 'callback');
|
||||
|
||||
this.configure('development', function(){
|
||||
this.set('json spaces', 2);
|
||||
});
|
||||
|
||||
this.configure('production', function(){
|
||||
this.enable('view cache');
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* Proxy `connect#use()` to apply settings to
|
||||
* mounted applications.
|
||||
*
|
||||
* @param {String|Function|Server} route
|
||||
* @param {Function|Server} fn
|
||||
* @return {app} for chaining
|
||||
* @api public
|
||||
*/
|
||||
|
||||
app.use = function(route, fn){
|
||||
var app;
|
||||
|
||||
// default route to '/'
|
||||
if ('string' != typeof route) fn = route, route = '/';
|
||||
|
||||
// express app
|
||||
if (fn.handle && fn.set) app = fn;
|
||||
|
||||
// restore .app property on req and res
|
||||
if (app) {
|
||||
app.route = route;
|
||||
fn = function(req, res, next) {
|
||||
var orig = req.app;
|
||||
app.handle(req, res, function(err){
|
||||
req.app = res.app = orig;
|
||||
req.__proto__ = orig.request;
|
||||
res.__proto__ = orig.response;
|
||||
next(err);
|
||||
});
|
||||
};
|
||||
}
|
||||
|
||||
connect.proto.use.call(this, route, fn);
|
||||
|
||||
// mounted an app
|
||||
if (app) {
|
||||
app.parent = this;
|
||||
app.emit('mount', this);
|
||||
}
|
||||
|
||||
return this;
|
||||
};
|
||||
|
||||
/**
|
||||
* Register the given template engine callback `fn`
|
||||
* as `ext`.
|
||||
*
|
||||
* By default will `require()` the engine based on the
|
||||
* file extension. For example if you try to render
|
||||
* a "foo.jade" file Express will invoke the following internally:
|
||||
*
|
||||
* app.engine('jade', require('jade').__express);
|
||||
*
|
||||
* For engines that do not provide `.__express` out of the box,
|
||||
* or if you wish to "map" a different extension to the template engine
|
||||
* you may use this method. For example mapping the EJS template engine to
|
||||
* ".html" files:
|
||||
*
|
||||
* app.engine('html', require('ejs').renderFile);
|
||||
*
|
||||
* In this case EJS provides a `.renderFile()` method with
|
||||
* the same signature that Express expects: `(path, options, callback)`,
|
||||
* though note that it aliases this method as `ejs.__express` internally
|
||||
* 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)
|
||||
* library was created to map all of node's popular template
|
||||
* engines to follow this convention, thus allowing them to
|
||||
* work seamlessly within Express.
|
||||
*
|
||||
* @param {String} ext
|
||||
* @param {Function} fn
|
||||
* @return {app} for chaining
|
||||
* @api public
|
||||
*/
|
||||
|
||||
app.engine = function(ext, fn){
|
||||
if ('function' != typeof fn) throw new Error('callback function required');
|
||||
if ('.' != ext[0]) ext = '.' + ext;
|
||||
this.engines[ext] = fn;
|
||||
return this;
|
||||
};
|
||||
|
||||
/**
|
||||
* Map the given param placeholder `name`(s) to the given callback(s).
|
||||
*
|
||||
* Parameter mapping is used to provide pre-conditions to routes
|
||||
* which use normalized placeholders. For example a _:user_id_ parameter
|
||||
* could automatically load a user's information from the database without
|
||||
* any additional code,
|
||||
*
|
||||
* The callback uses the samesignature as middleware, the only differencing
|
||||
* being that the value of the placeholder is passed, in this case the _id_
|
||||
* of the user. Once the `next()` function is invoked, just like middleware
|
||||
* it will continue on to execute the route, or subsequent parameter functions.
|
||||
*
|
||||
* app.param('user_id', function(req, res, next, id){
|
||||
* User.find(id, function(err, user){
|
||||
* if (err) {
|
||||
* next(err);
|
||||
* } else if (user) {
|
||||
* req.user = user;
|
||||
* next();
|
||||
* } else {
|
||||
* next(new Error('failed to load user'));
|
||||
* }
|
||||
* });
|
||||
* });
|
||||
*
|
||||
* @param {String|Array} name
|
||||
* @param {Function} fn
|
||||
* @return {app} for chaining
|
||||
* @api public
|
||||
*/
|
||||
|
||||
app.param = function(name, fn){
|
||||
var self = this
|
||||
, fns = [].slice.call(arguments, 1);
|
||||
|
||||
// array
|
||||
if (Array.isArray(name)) {
|
||||
name.forEach(function(name){
|
||||
fns.forEach(function(fn){
|
||||
self.param(name, fn);
|
||||
});
|
||||
});
|
||||
// param logic
|
||||
} else if ('function' == typeof name) {
|
||||
this._router.param(name);
|
||||
// single
|
||||
} else {
|
||||
if (':' == name[0]) name = name.substr(1);
|
||||
fns.forEach(function(fn){
|
||||
self._router.param(name, fn);
|
||||
});
|
||||
}
|
||||
|
||||
return this;
|
||||
};
|
||||
|
||||
/**
|
||||
* Assign `setting` to `val`, or return `setting`'s value.
|
||||
*
|
||||
* app.set('foo', 'bar');
|
||||
* app.get('foo');
|
||||
* // => "bar"
|
||||
*
|
||||
* Mounted servers inherit their parent server's settings.
|
||||
*
|
||||
* @param {String} setting
|
||||
* @param {String} val
|
||||
* @return {Server} for chaining
|
||||
* @api public
|
||||
*/
|
||||
|
||||
app.set = function(setting, val){
|
||||
if (1 == arguments.length) {
|
||||
return this.settings[setting];
|
||||
} else {
|
||||
this.settings[setting] = val;
|
||||
return this;
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Return the app's absolute pathname
|
||||
* based on the parent(s) that have
|
||||
* mounted it.
|
||||
*
|
||||
* For example if the application was
|
||||
* mounted as "/admin", which itself
|
||||
* was mounted as "/blog" then the
|
||||
* return value would be "/blog/admin".
|
||||
*
|
||||
* @return {String}
|
||||
* @api private
|
||||
*/
|
||||
|
||||
app.path = function(){
|
||||
return this.parent
|
||||
? this.parent.path() + this.route
|
||||
: '';
|
||||
};
|
||||
|
||||
/**
|
||||
* Check if `setting` is enabled (truthy).
|
||||
*
|
||||
* app.enabled('foo')
|
||||
* // => false
|
||||
*
|
||||
* app.enable('foo')
|
||||
* app.enabled('foo')
|
||||
* // => true
|
||||
*
|
||||
* @param {String} setting
|
||||
* @return {Boolean}
|
||||
* @api public
|
||||
*/
|
||||
|
||||
app.enabled = function(setting){
|
||||
return !!this.set(setting);
|
||||
};
|
||||
|
||||
/**
|
||||
* Check if `setting` is disabled.
|
||||
*
|
||||
* app.disabled('foo')
|
||||
* // => true
|
||||
*
|
||||
* app.enable('foo')
|
||||
* app.disabled('foo')
|
||||
* // => false
|
||||
*
|
||||
* @param {String} setting
|
||||
* @return {Boolean}
|
||||
* @api public
|
||||
*/
|
||||
|
||||
app.disabled = function(setting){
|
||||
return !this.set(setting);
|
||||
};
|
||||
|
||||
/**
|
||||
* Enable `setting`.
|
||||
*
|
||||
* @param {String} setting
|
||||
* @return {app} for chaining
|
||||
* @api public
|
||||
*/
|
||||
|
||||
app.enable = function(setting){
|
||||
return this.set(setting, true);
|
||||
};
|
||||
|
||||
/**
|
||||
* Disable `setting`.
|
||||
*
|
||||
* @param {String} setting
|
||||
* @return {app} for chaining
|
||||
* @api public
|
||||
*/
|
||||
|
||||
app.disable = function(setting){
|
||||
return this.set(setting, false);
|
||||
};
|
||||
|
||||
/**
|
||||
* Configure callback for zero or more envs,
|
||||
* when no `env` is specified that callback will
|
||||
* be invoked for all environments. Any combination
|
||||
* can be used multiple times, in any order desired.
|
||||
*
|
||||
* Examples:
|
||||
*
|
||||
* app.configure(function(){
|
||||
* // executed for all envs
|
||||
* });
|
||||
*
|
||||
* app.configure('stage', function(){
|
||||
* // executed staging env
|
||||
* });
|
||||
*
|
||||
* app.configure('stage', 'production', function(){
|
||||
* // executed for stage and production
|
||||
* });
|
||||
*
|
||||
* Note:
|
||||
*
|
||||
* These callbacks are invoked immediately, and
|
||||
* are effectively sugar for the following:
|
||||
*
|
||||
* var env = process.env.NODE_ENV || 'development';
|
||||
*
|
||||
* switch (env) {
|
||||
* case 'development':
|
||||
* ...
|
||||
* break;
|
||||
* case 'stage':
|
||||
* ...
|
||||
* break;
|
||||
* case 'production':
|
||||
* ...
|
||||
* break;
|
||||
* }
|
||||
*
|
||||
* @param {String} env...
|
||||
* @param {Function} fn
|
||||
* @return {app} for chaining
|
||||
* @api public
|
||||
*/
|
||||
|
||||
app.configure = function(env, fn){
|
||||
var envs = 'all'
|
||||
, args = [].slice.call(arguments);
|
||||
fn = args.pop();
|
||||
if (args.length) envs = args;
|
||||
if ('all' == envs || ~envs.indexOf(this.settings.env)) fn.call(this);
|
||||
return this;
|
||||
};
|
||||
|
||||
/**
|
||||
* Delegate `.VERB(...)` calls to `router.VERB(...)`.
|
||||
*/
|
||||
|
||||
methods.forEach(function(method){
|
||||
app[method] = function(path){
|
||||
if ('get' == method && 1 == arguments.length) return this.set(path);
|
||||
|
||||
// if no router attached yet, attach the router
|
||||
if (!this._usedRouter) this.use(this.router);
|
||||
|
||||
// setup route
|
||||
this._router[method].apply(this._router, arguments);
|
||||
return this;
|
||||
};
|
||||
});
|
||||
|
||||
/**
|
||||
* Special-cased "all" method, applying the given route `path`,
|
||||
* middleware, and callback to _every_ HTTP method.
|
||||
*
|
||||
* @param {String} path
|
||||
* @param {Function} ...
|
||||
* @return {app} for chaining
|
||||
* @api public
|
||||
*/
|
||||
|
||||
app.all = function(path){
|
||||
var args = arguments;
|
||||
methods.forEach(function(method){
|
||||
app[method].apply(this, args);
|
||||
}, this);
|
||||
return this;
|
||||
};
|
||||
|
||||
// del -> delete alias
|
||||
|
||||
app.del = app.delete;
|
||||
|
||||
/**
|
||||
* Render the given view `name` name with `options`
|
||||
* and a callback accepting an error and the
|
||||
* rendered template string.
|
||||
*
|
||||
* Example:
|
||||
*
|
||||
* app.render('email', { name: 'Tobi' }, function(err, html){
|
||||
* // ...
|
||||
* })
|
||||
*
|
||||
* @param {String} name
|
||||
* @param {String|Function} options or fn
|
||||
* @param {Function} fn
|
||||
* @api public
|
||||
*/
|
||||
|
||||
app.render = function(name, options, fn){
|
||||
var opts = {}
|
||||
, cache = this.cache
|
||||
, engines = this.engines
|
||||
, view;
|
||||
|
||||
// support callback function as second arg
|
||||
if ('function' == typeof options) {
|
||||
fn = options, options = {};
|
||||
}
|
||||
|
||||
// merge app.locals
|
||||
utils.merge(opts, this.locals);
|
||||
|
||||
// merge options._locals
|
||||
if (options._locals) utils.merge(opts, options._locals);
|
||||
|
||||
// merge options
|
||||
utils.merge(opts, options);
|
||||
|
||||
// set .cache unless explicitly provided
|
||||
opts.cache = null == opts.cache
|
||||
? this.enabled('view cache')
|
||||
: opts.cache;
|
||||
|
||||
// primed cache
|
||||
if (opts.cache) view = cache[name];
|
||||
|
||||
// view
|
||||
if (!view) {
|
||||
view = new View(name, {
|
||||
defaultEngine: this.get('view engine'),
|
||||
root: this.get('views'),
|
||||
engines: engines
|
||||
});
|
||||
|
||||
if (!view.path) {
|
||||
var err = new Error('Failed to lookup view "' + name + '"');
|
||||
err.view = view;
|
||||
return fn(err);
|
||||
}
|
||||
|
||||
// prime the cache
|
||||
if (opts.cache) cache[name] = view;
|
||||
}
|
||||
|
||||
// render
|
||||
try {
|
||||
view.render(opts, fn);
|
||||
} catch (err) {
|
||||
fn(err);
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Listen for connections.
|
||||
*
|
||||
* A node `http.Server` is returned, with this
|
||||
* application (which is a `Function`) as its
|
||||
* callback. If you wish to create both an HTTP
|
||||
* and HTTPS server you may do so with the "http"
|
||||
* and "https" modules as shown here:
|
||||
*
|
||||
* var http = require('http')
|
||||
* , https = require('https')
|
||||
* , express = require('express')
|
||||
* , app = express();
|
||||
*
|
||||
* http.createServer(app).listen(80);
|
||||
* https.createServer({ ... }, app).listen(443);
|
||||
*
|
||||
* @return {http.Server}
|
||||
* @api public
|
||||
*/
|
||||
|
||||
app.listen = function(){
|
||||
var server = http.createServer(this);
|
||||
return server.listen.apply(server, arguments);
|
||||
};
|
|
@ -1,92 +0,0 @@
|
|||
/**
|
||||
* Module dependencies.
|
||||
*/
|
||||
|
||||
var connect = require('connect')
|
||||
, proto = require('./application')
|
||||
, Route = require('./router/route')
|
||||
, Router = require('./router')
|
||||
, req = require('./request')
|
||||
, res = require('./response')
|
||||
, utils = connect.utils;
|
||||
|
||||
/**
|
||||
* Expose `createApplication()`.
|
||||
*/
|
||||
|
||||
exports = module.exports = createApplication;
|
||||
|
||||
/**
|
||||
* Framework version.
|
||||
*/
|
||||
|
||||
exports.version = '3.1.2';
|
||||
|
||||
/**
|
||||
* Expose mime.
|
||||
*/
|
||||
|
||||
exports.mime = connect.mime;
|
||||
|
||||
/**
|
||||
* Create an express application.
|
||||
*
|
||||
* @return {Function}
|
||||
* @api public
|
||||
*/
|
||||
|
||||
function createApplication() {
|
||||
var app = connect();
|
||||
utils.merge(app, proto);
|
||||
app.request = { __proto__: req };
|
||||
app.response = { __proto__: res };
|
||||
app.init();
|
||||
return app;
|
||||
}
|
||||
|
||||
/**
|
||||
* Expose connect.middleware as express.*
|
||||
* for example `express.logger` etc.
|
||||
*/
|
||||
|
||||
for (var key in connect.middleware) {
|
||||
Object.defineProperty(
|
||||
exports
|
||||
, key
|
||||
, Object.getOwnPropertyDescriptor(connect.middleware, key));
|
||||
}
|
||||
|
||||
/**
|
||||
* Error on createServer().
|
||||
*/
|
||||
|
||||
exports.createServer = function(){
|
||||
console.warn('Warning: express.createServer() is deprecated, express');
|
||||
console.warn('applications no longer inherit from http.Server,');
|
||||
console.warn('please use:');
|
||||
console.warn('');
|
||||
console.warn(' var express = require("express");');
|
||||
console.warn(' var app = express();');
|
||||
console.warn('');
|
||||
return createApplication();
|
||||
};
|
||||
|
||||
/**
|
||||
* Expose the prototypes.
|
||||
*/
|
||||
|
||||
exports.application = proto;
|
||||
exports.request = req;
|
||||
exports.response = res;
|
||||
|
||||
/**
|
||||
* Expose constructors.
|
||||
*/
|
||||
|
||||
exports.Route = Route;
|
||||
exports.Router = Router;
|
||||
|
||||
// Error handler title
|
||||
|
||||
exports.errorHandler.title = 'Express';
|
||||
|
|
@ -1,33 +0,0 @@
|
|||
|
||||
/**
|
||||
* Module dependencies.
|
||||
*/
|
||||
|
||||
var utils = require('./utils');
|
||||
|
||||
/**
|
||||
* Initialization middleware, exposing the
|
||||
* request and response to eachother, as well
|
||||
* as defaulting the X-Powered-By header field.
|
||||
*
|
||||
* @param {Function} app
|
||||
* @return {Function}
|
||||
* @api private
|
||||
*/
|
||||
|
||||
exports.init = function(app){
|
||||
return function expressInit(req, res, next){
|
||||
req.app = res.app = app;
|
||||
if (app.enabled('x-powered-by')) res.setHeader('X-Powered-By', 'Express');
|
||||
req.res = res;
|
||||
res.req = req;
|
||||
req.next = next;
|
||||
|
||||
req.__proto__ = app.request;
|
||||
res.__proto__ = app.response;
|
||||
|
||||
res.locals = res.locals || utils.locals(res);
|
||||
|
||||
next();
|
||||
}
|
||||
};
|
|
@ -1,496 +0,0 @@
|
|||
|
||||
/**
|
||||
* Module dependencies.
|
||||
*/
|
||||
|
||||
var http = require('http')
|
||||
, utils = require('./utils')
|
||||
, connect = require('connect')
|
||||
, fresh = require('fresh')
|
||||
, parseRange = require('range-parser')
|
||||
, parse = connect.utils.parseUrl
|
||||
, mime = connect.mime;
|
||||
|
||||
/**
|
||||
* Request prototype.
|
||||
*/
|
||||
|
||||
var req = exports = module.exports = {
|
||||
__proto__: http.IncomingMessage.prototype
|
||||
};
|
||||
|
||||
/**
|
||||
* Return request header.
|
||||
*
|
||||
* The `Referrer` header field is special-cased,
|
||||
* both `Referrer` and `Referer` are interchangeable.
|
||||
*
|
||||
* Examples:
|
||||
*
|
||||
* req.get('Content-Type');
|
||||
* // => "text/plain"
|
||||
*
|
||||
* req.get('content-type');
|
||||
* // => "text/plain"
|
||||
*
|
||||
* req.get('Something');
|
||||
* // => undefined
|
||||
*
|
||||
* Aliased as `req.header()`.
|
||||
*
|
||||
* @param {String} name
|
||||
* @return {String}
|
||||
* @api public
|
||||
*/
|
||||
|
||||
req.get =
|
||||
req.header = function(name){
|
||||
switch (name = name.toLowerCase()) {
|
||||
case 'referer':
|
||||
case 'referrer':
|
||||
return this.headers.referrer
|
||||
|| this.headers.referer;
|
||||
default:
|
||||
return this.headers[name];
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Check if the given `type(s)` is acceptable, returning
|
||||
* the best match when true, otherwise `undefined`, in which
|
||||
* case you should respond with 406 "Not Acceptable".
|
||||
*
|
||||
* The `type` value may be a single mime type string
|
||||
* such as "application/json", the extension name
|
||||
* such as "json", a comma-delimted list such as "json, html, text/plain",
|
||||
* or an array `["json", "html", "text/plain"]`. When a list
|
||||
* or array is given the _best_ match, if any is returned.
|
||||
*
|
||||
* Examples:
|
||||
*
|
||||
* // Accept: text/html
|
||||
* req.accepts('html');
|
||||
* // => "html"
|
||||
*
|
||||
* // Accept: text/*, application/json
|
||||
* req.accepts('html');
|
||||
* // => "html"
|
||||
* req.accepts('text/html');
|
||||
* // => "text/html"
|
||||
* req.accepts('json, text');
|
||||
* // => "json"
|
||||
* req.accepts('application/json');
|
||||
* // => "application/json"
|
||||
*
|
||||
* // Accept: text/*, application/json
|
||||
* req.accepts('image/png');
|
||||
* req.accepts('png');
|
||||
* // => undefined
|
||||
*
|
||||
* // Accept: text/*;q=.5, application/json
|
||||
* req.accepts(['html', 'json']);
|
||||
* req.accepts('html, json');
|
||||
* // => "json"
|
||||
*
|
||||
* @param {String|Array} type(s)
|
||||
* @return {String}
|
||||
* @api public
|
||||
*/
|
||||
|
||||
req.accepts = function(type){
|
||||
return utils.accepts(type, this.get('Accept'));
|
||||
};
|
||||
|
||||
/**
|
||||
* Check if the given `charset` is acceptable,
|
||||
* otherwise you should respond with 406 "Not Acceptable".
|
||||
*
|
||||
* @param {String} charset
|
||||
* @return {Boolean}
|
||||
* @api public
|
||||
*/
|
||||
|
||||
req.acceptsCharset = function(charset){
|
||||
var accepted = this.acceptedCharsets;
|
||||
return accepted.length
|
||||
? ~accepted.indexOf(charset)
|
||||
: true;
|
||||
};
|
||||
|
||||
/**
|
||||
* Check if the given `lang` is acceptable,
|
||||
* otherwise you should respond with 406 "Not Acceptable".
|
||||
*
|
||||
* @param {String} lang
|
||||
* @return {Boolean}
|
||||
* @api public
|
||||
*/
|
||||
|
||||
req.acceptsLanguage = function(lang){
|
||||
var accepted = this.acceptedLanguages;
|
||||
return accepted.length
|
||||
? ~accepted.indexOf(lang)
|
||||
: true;
|
||||
};
|
||||
|
||||
/**
|
||||
* Parse Range header field,
|
||||
* capping to the given `size`.
|
||||
*
|
||||
* Unspecified ranges such as "0-" require
|
||||
* knowledge of your resource length. In
|
||||
* the case of a byte range this is of course
|
||||
* the total number of bytes. If the Range
|
||||
* header field is not given `null` is returned,
|
||||
* `-1` when unsatisfiable, `-2` when syntactically invalid.
|
||||
*
|
||||
* NOTE: remember that ranges are inclusive, so
|
||||
* for example "Range: users=0-3" should respond
|
||||
* with 4 users when available, not 3.
|
||||
*
|
||||
* @param {Number} size
|
||||
* @return {Array}
|
||||
* @api public
|
||||
*/
|
||||
|
||||
req.range = function(size){
|
||||
var range = this.get('Range');
|
||||
if (!range) return;
|
||||
return parseRange(size, range);
|
||||
};
|
||||
|
||||
/**
|
||||
* Return an array of Accepted media types
|
||||
* ordered from highest quality to lowest.
|
||||
*
|
||||
* Examples:
|
||||
*
|
||||
* [ { value: 'application/json',
|
||||
* quality: 1,
|
||||
* type: 'application',
|
||||
* subtype: 'json' },
|
||||
* { value: 'text/html',
|
||||
* quality: 0.5,
|
||||
* type: 'text',
|
||||
* subtype: 'html' } ]
|
||||
*
|
||||
* @return {Array}
|
||||
* @api public
|
||||
*/
|
||||
|
||||
req.__defineGetter__('accepted', function(){
|
||||
var accept = this.get('Accept');
|
||||
return accept
|
||||
? utils.parseAccept(accept)
|
||||
: [];
|
||||
});
|
||||
|
||||
/**
|
||||
* Return an array of Accepted languages
|
||||
* ordered from highest quality to lowest.
|
||||
*
|
||||
* Examples:
|
||||
*
|
||||
* Accept-Language: en;q=.5, en-us
|
||||
* ['en-us', 'en']
|
||||
*
|
||||
* @return {Array}
|
||||
* @api public
|
||||
*/
|
||||
|
||||
req.__defineGetter__('acceptedLanguages', function(){
|
||||
var accept = this.get('Accept-Language');
|
||||
return accept
|
||||
? utils
|
||||
.parseParams(accept)
|
||||
.map(function(obj){
|
||||
return obj.value;
|
||||
})
|
||||
: [];
|
||||
});
|
||||
|
||||
/**
|
||||
* Return an array of Accepted charsets
|
||||
* ordered from highest quality to lowest.
|
||||
*
|
||||
* Examples:
|
||||
*
|
||||
* Accept-Charset: iso-8859-5;q=.2, unicode-1-1;q=0.8
|
||||
* ['unicode-1-1', 'iso-8859-5']
|
||||
*
|
||||
* @return {Array}
|
||||
* @api public
|
||||
*/
|
||||
|
||||
req.__defineGetter__('acceptedCharsets', function(){
|
||||
var accept = this.get('Accept-Charset');
|
||||
return accept
|
||||
? utils
|
||||
.parseParams(accept)
|
||||
.map(function(obj){
|
||||
return obj.value;
|
||||
})
|
||||
: [];
|
||||
});
|
||||
|
||||
/**
|
||||
* Return the value of param `name` when present or `defaultValue`.
|
||||
*
|
||||
* - Checks route placeholders, ex: _/user/:id_
|
||||
* - Checks body params, ex: id=12, {"id":12}
|
||||
* - Checks query string params, ex: ?id=12
|
||||
*
|
||||
* To utilize request bodies, `req.body`
|
||||
* should be an object. This can be done by using
|
||||
* the `connect.bodyParser()` middleware.
|
||||
*
|
||||
* @param {String} name
|
||||
* @param {Mixed} [defaultValue]
|
||||
* @return {String}
|
||||
* @api public
|
||||
*/
|
||||
|
||||
req.param = function(name, defaultValue){
|
||||
var params = this.params || {};
|
||||
var body = this.body || {};
|
||||
var query = this.query || {};
|
||||
if (null != params[name] && params.hasOwnProperty(name)) return params[name];
|
||||
if (null != body[name]) return body[name];
|
||||
if (null != query[name]) return query[name];
|
||||
return defaultValue;
|
||||
};
|
||||
|
||||
/**
|
||||
* Check if the incoming request contains the "Content-Type"
|
||||
* header field, and it contains the give mime `type`.
|
||||
*
|
||||
* Examples:
|
||||
*
|
||||
* // With Content-Type: text/html; charset=utf-8
|
||||
* req.is('html');
|
||||
* req.is('text/html');
|
||||
* req.is('text/*');
|
||||
* // => true
|
||||
*
|
||||
* // When Content-Type is application/json
|
||||
* req.is('json');
|
||||
* req.is('application/json');
|
||||
* req.is('application/*');
|
||||
* // => true
|
||||
*
|
||||
* req.is('html');
|
||||
* // => false
|
||||
*
|
||||
* @param {String} type
|
||||
* @return {Boolean}
|
||||
* @api public
|
||||
*/
|
||||
|
||||
req.is = function(type){
|
||||
var ct = this.get('Content-Type');
|
||||
if (!ct) return false;
|
||||
ct = ct.split(';')[0];
|
||||
if (!~type.indexOf('/')) type = mime.lookup(type);
|
||||
if (~type.indexOf('*')) {
|
||||
type = type.split('/');
|
||||
ct = ct.split('/');
|
||||
if ('*' == type[0] && type[1] == ct[1]) return true;
|
||||
if ('*' == type[1] && type[0] == ct[0]) return true;
|
||||
return false;
|
||||
}
|
||||
return !! ~ct.indexOf(type);
|
||||
};
|
||||
|
||||
/**
|
||||
* Return the protocol string "http" or "https"
|
||||
* when requested with TLS. When the "trust proxy"
|
||||
* setting is enabled the "X-Forwarded-Proto" header
|
||||
* field will be trusted. If you're running behind
|
||||
* a reverse proxy that supplies https for you this
|
||||
* may be enabled.
|
||||
*
|
||||
* @return {String}
|
||||
* @api public
|
||||
*/
|
||||
|
||||
req.__defineGetter__('protocol', function(){
|
||||
var trustProxy = this.app.get('trust proxy');
|
||||
return this.connection.encrypted
|
||||
? 'https'
|
||||
: trustProxy
|
||||
? (this.get('X-Forwarded-Proto') || 'http')
|
||||
: 'http';
|
||||
});
|
||||
|
||||
/**
|
||||
* Short-hand for:
|
||||
*
|
||||
* req.protocol == 'https'
|
||||
*
|
||||
* @return {Boolean}
|
||||
* @api public
|
||||
*/
|
||||
|
||||
req.__defineGetter__('secure', function(){
|
||||
return 'https' == this.protocol;
|
||||
});
|
||||
|
||||
/**
|
||||
* Return the remote address, or when
|
||||
* "trust proxy" is `true` return
|
||||
* the upstream addr.
|
||||
*
|
||||
* @return {String}
|
||||
* @api public
|
||||
*/
|
||||
|
||||
req.__defineGetter__('ip', function(){
|
||||
return this.ips[0] || this.connection.remoteAddress;
|
||||
});
|
||||
|
||||
/**
|
||||
* When "trust proxy" is `true`, parse
|
||||
* the "X-Forwarded-For" ip address list.
|
||||
*
|
||||
* For example if the value were "client, proxy1, proxy2"
|
||||
* you would receive the array `["client", "proxy1", "proxy2"]`
|
||||
* where "proxy2" is the furthest down-stream.
|
||||
*
|
||||
* @return {Array}
|
||||
* @api public
|
||||
*/
|
||||
|
||||
req.__defineGetter__('ips', function(){
|
||||
var trustProxy = this.app.get('trust proxy');
|
||||
var val = this.get('X-Forwarded-For');
|
||||
return trustProxy && val
|
||||
? val.split(/ *, */)
|
||||
: [];
|
||||
});
|
||||
|
||||
/**
|
||||
* Return basic auth credentials.
|
||||
*
|
||||
* Examples:
|
||||
*
|
||||
* // http://tobi:hello@example.com
|
||||
* req.auth
|
||||
* // => { username: 'tobi', password: 'hello' }
|
||||
*
|
||||
* @return {Object} or undefined
|
||||
* @api public
|
||||
*/
|
||||
|
||||
req.__defineGetter__('auth', function(){
|
||||
// missing
|
||||
var auth = this.get('Authorization');
|
||||
if (!auth) return;
|
||||
|
||||
// malformed
|
||||
var parts = auth.split(' ');
|
||||
if ('basic' != parts[0].toLowerCase()) return;
|
||||
if (!parts[1]) return;
|
||||
auth = parts[1];
|
||||
|
||||
// credentials
|
||||
auth = new Buffer(auth, 'base64').toString().match(/^([^:]*):(.*)$/);
|
||||
if (!auth) return;
|
||||
return { username: auth[1], password: auth[2] };
|
||||
});
|
||||
|
||||
/**
|
||||
* Return subdomains as an array.
|
||||
*
|
||||
* Subdomains are the dot-separated parts of the host before the main domain of
|
||||
* the app. By default, the domain of the app is assumed to be the last two
|
||||
* parts of the host. This can be changed by setting "subdomain offset".
|
||||
*
|
||||
* For example, if the domain is "tobi.ferrets.example.com":
|
||||
* If "subdomain offset" is not set, req.subdomains is `["ferrets", "tobi"]`.
|
||||
* If "subdomain offset" is 3, req.subdomains is `["tobi"]`.
|
||||
*
|
||||
* @return {Array}
|
||||
* @api public
|
||||
*/
|
||||
|
||||
req.__defineGetter__('subdomains', function(){
|
||||
var offset = this.app.get('subdomain offset');
|
||||
return this.get('Host')
|
||||
.split('.')
|
||||
.reverse()
|
||||
.slice(offset);
|
||||
});
|
||||
|
||||
/**
|
||||
* Short-hand for `url.parse(req.url).pathname`.
|
||||
*
|
||||
* @return {String}
|
||||
* @api public
|
||||
*/
|
||||
|
||||
req.__defineGetter__('path', function(){
|
||||
return parse(this).pathname;
|
||||
});
|
||||
|
||||
/**
|
||||
* Parse the "Host" header field hostname.
|
||||
*
|
||||
* @return {String}
|
||||
* @api public
|
||||
*/
|
||||
|
||||
req.__defineGetter__('host', function(){
|
||||
var trustProxy = this.app.get('trust proxy');
|
||||
var host = trustProxy && this.get('X-Forwarded-Host');
|
||||
host = host || this.get('Host');
|
||||
return host.split(':')[0];
|
||||
});
|
||||
|
||||
/**
|
||||
* Check if the request is fresh, aka
|
||||
* Last-Modified and/or the ETag
|
||||
* still match.
|
||||
*
|
||||
* @return {Boolean}
|
||||
* @api public
|
||||
*/
|
||||
|
||||
req.__defineGetter__('fresh', function(){
|
||||
var method = this.method;
|
||||
var s = this.res.statusCode;
|
||||
|
||||
// GET or HEAD for weak freshness validation only
|
||||
if ('GET' != method && 'HEAD' != method) return false;
|
||||
|
||||
// 2xx or 304 as per rfc2616 14.26
|
||||
if ((s >= 200 && s < 300) || 304 == s) {
|
||||
return fresh(this.headers, this.res._headers);
|
||||
}
|
||||
|
||||
return false;
|
||||
});
|
||||
|
||||
/**
|
||||
* Check if the request is stale, aka
|
||||
* "Last-Modified" and / or the "ETag" for the
|
||||
* resource has changed.
|
||||
*
|
||||
* @return {Boolean}
|
||||
* @api public
|
||||
*/
|
||||
|
||||
req.__defineGetter__('stale', function(){
|
||||
return !this.fresh;
|
||||
});
|
||||
|
||||
/**
|
||||
* Check if the request was an _XMLHttpRequest_.
|
||||
*
|
||||
* @return {Boolean}
|
||||
* @api public
|
||||
*/
|
||||
|
||||
req.__defineGetter__('xhr', function(){
|
||||
var val = this.get('X-Requested-With') || '';
|
||||
return 'xmlhttprequest' == val.toLowerCase();
|
||||
});
|
|
@ -1,756 +0,0 @@
|
|||
/**
|
||||
* Module dependencies.
|
||||
*/
|
||||
|
||||
var http = require('http')
|
||||
, path = require('path')
|
||||
, connect = require('connect')
|
||||
, utils = connect.utils
|
||||
, sign = require('cookie-signature').sign
|
||||
, normalizeType = require('./utils').normalizeType
|
||||
, normalizeTypes = require('./utils').normalizeTypes
|
||||
, etag = require('./utils').etag
|
||||
, statusCodes = http.STATUS_CODES
|
||||
, cookie = require('cookie')
|
||||
, send = require('send')
|
||||
, mime = connect.mime
|
||||
, basename = path.basename
|
||||
, extname = path.extname
|
||||
, join = path.join;
|
||||
|
||||
/**
|
||||
* Response prototype.
|
||||
*/
|
||||
|
||||
var res = module.exports = {
|
||||
__proto__: http.ServerResponse.prototype
|
||||
};
|
||||
|
||||
/**
|
||||
* Set status `code`.
|
||||
*
|
||||
* @param {Number} code
|
||||
* @return {ServerResponse}
|
||||
* @api public
|
||||
*/
|
||||
|
||||
res.status = function(code){
|
||||
this.statusCode = code;
|
||||
return this;
|
||||
};
|
||||
|
||||
/**
|
||||
* Set Link header field with the given `links`.
|
||||
*
|
||||
* Examples:
|
||||
*
|
||||
* res.links({
|
||||
* next: 'http://api.example.com/users?page=2',
|
||||
* last: 'http://api.example.com/users?page=5'
|
||||
* });
|
||||
*
|
||||
* @param {Object} links
|
||||
* @return {ServerResponse}
|
||||
* @api public
|
||||
*/
|
||||
|
||||
res.links = function(links){
|
||||
return this.set('Link', Object.keys(links).map(function(rel){
|
||||
return '<' + links[rel] + '>; rel="' + rel + '"';
|
||||
}).join(', '));
|
||||
};
|
||||
|
||||
/**
|
||||
* Send a response.
|
||||
*
|
||||
* Examples:
|
||||
*
|
||||
* res.send(new Buffer('wahoo'));
|
||||
* res.send({ some: 'json' });
|
||||
* res.send('<p>some html</p>');
|
||||
* res.send(404, 'Sorry, cant find that');
|
||||
* res.send(404);
|
||||
*
|
||||
* @param {Mixed} body or status
|
||||
* @param {Mixed} body
|
||||
* @return {ServerResponse}
|
||||
* @api public
|
||||
*/
|
||||
|
||||
res.send = function(body){
|
||||
var req = this.req
|
||||
, head = 'HEAD' == req.method
|
||||
, len;
|
||||
|
||||
// allow status / body
|
||||
if (2 == arguments.length) {
|
||||
// res.send(body, status) backwards compat
|
||||
if ('number' != typeof body && 'number' == typeof arguments[1]) {
|
||||
this.statusCode = arguments[1];
|
||||
} else {
|
||||
this.statusCode = body;
|
||||
body = arguments[1];
|
||||
}
|
||||
}
|
||||
|
||||
switch (typeof body) {
|
||||
// response status
|
||||
case 'number':
|
||||
this.get('Content-Type') || this.type('txt');
|
||||
this.statusCode = body;
|
||||
body = http.STATUS_CODES[body];
|
||||
break;
|
||||
// string defaulting to html
|
||||
case 'string':
|
||||
if (!this.get('Content-Type')) {
|
||||
this.charset = this.charset || 'utf-8';
|
||||
this.type('html');
|
||||
}
|
||||
break;
|
||||
case 'boolean':
|
||||
case 'object':
|
||||
if (null == body) {
|
||||
body = '';
|
||||
} else if (Buffer.isBuffer(body)) {
|
||||
this.get('Content-Type') || this.type('bin');
|
||||
} else {
|
||||
return this.json(body);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
// populate Content-Length
|
||||
if (undefined !== body && !this.get('Content-Length')) {
|
||||
this.set('Content-Length', len = Buffer.isBuffer(body)
|
||||
? body.length
|
||||
: Buffer.byteLength(body));
|
||||
}
|
||||
|
||||
// ETag support
|
||||
// TODO: W/ support
|
||||
if (len > 1024) {
|
||||
if (!this.get('ETag')) {
|
||||
this.set('ETag', etag(body));
|
||||
}
|
||||
}
|
||||
|
||||
// freshness
|
||||
if (req.fresh) this.statusCode = 304;
|
||||
|
||||
// strip irrelevant headers
|
||||
if (204 == this.statusCode || 304 == this.statusCode) {
|
||||
this.removeHeader('Content-Type');
|
||||
this.removeHeader('Content-Length');
|
||||
this.removeHeader('Transfer-Encoding');
|
||||
body = '';
|
||||
}
|
||||
|
||||
// respond
|
||||
this.end(head ? null : body);
|
||||
return this;
|
||||
};
|
||||
|
||||
/**
|
||||
* Send JSON response.
|
||||
*
|
||||
* Examples:
|
||||
*
|
||||
* res.json(null);
|
||||
* res.json({ user: 'tj' });
|
||||
* res.json(500, 'oh noes!');
|
||||
* res.json(404, 'I dont have that');
|
||||
*
|
||||
* @param {Mixed} obj or status
|
||||
* @param {Mixed} obj
|
||||
* @return {ServerResponse}
|
||||
* @api public
|
||||
*/
|
||||
|
||||
res.json = function(obj){
|
||||
// allow status / body
|
||||
if (2 == arguments.length) {
|
||||
// res.json(body, status) backwards compat
|
||||
if ('number' == typeof arguments[1]) {
|
||||
this.statusCode = arguments[1];
|
||||
} else {
|
||||
this.statusCode = obj;
|
||||
obj = arguments[1];
|
||||
}
|
||||
}
|
||||
|
||||
// settings
|
||||
var app = this.app;
|
||||
var replacer = app.get('json replacer');
|
||||
var spaces = app.get('json spaces');
|
||||
var body = JSON.stringify(obj, replacer, spaces);
|
||||
|
||||
// content-type
|
||||
this.charset = this.charset || 'utf-8';
|
||||
this.get('Content-Type') || this.set('Content-Type', 'application/json');
|
||||
|
||||
return this.send(body);
|
||||
};
|
||||
|
||||
/**
|
||||
* Send JSON response with JSONP callback support.
|
||||
*
|
||||
* Examples:
|
||||
*
|
||||
* res.jsonp(null);
|
||||
* res.jsonp({ user: 'tj' });
|
||||
* res.jsonp(500, 'oh noes!');
|
||||
* res.jsonp(404, 'I dont have that');
|
||||
*
|
||||
* @param {Mixed} obj or status
|
||||
* @param {Mixed} obj
|
||||
* @return {ServerResponse}
|
||||
* @api public
|
||||
*/
|
||||
|
||||
res.jsonp = function(obj){
|
||||
// allow status / body
|
||||
if (2 == arguments.length) {
|
||||
// res.json(body, status) backwards compat
|
||||
if ('number' == typeof arguments[1]) {
|
||||
this.statusCode = arguments[1];
|
||||
} else {
|
||||
this.statusCode = obj;
|
||||
obj = arguments[1];
|
||||
}
|
||||
}
|
||||
|
||||
// settings
|
||||
var app = this.app;
|
||||
var replacer = app.get('json replacer');
|
||||
var spaces = app.get('json spaces');
|
||||
var body = JSON.stringify(obj, replacer, spaces)
|
||||
.replace(/\u2028/g, '\\u2028')
|
||||
.replace(/\u2029/g, '\\u2029');
|
||||
var callback = this.req.query[app.get('jsonp callback name')];
|
||||
|
||||
// content-type
|
||||
this.charset = this.charset || 'utf-8';
|
||||
this.set('Content-Type', 'application/json');
|
||||
|
||||
// jsonp
|
||||
if (callback) {
|
||||
this.set('Content-Type', 'text/javascript');
|
||||
var cb = callback.replace(/[^\[\]\w$.]/g, '');
|
||||
body = cb + ' && ' + cb + '(' + body + ');';
|
||||
}
|
||||
|
||||
return this.send(body);
|
||||
};
|
||||
|
||||
/**
|
||||
* Transfer the file at the given `path`.
|
||||
*
|
||||
* Automatically sets the _Content-Type_ response header field.
|
||||
* The callback `fn(err)` is invoked when the transfer is complete
|
||||
* or when an error occurs. Be sure to check `res.sentHeader`
|
||||
* if you wish to attempt responding, as the header and some data
|
||||
* may have already been transferred.
|
||||
*
|
||||
* Options:
|
||||
*
|
||||
* - `maxAge` defaulting to 0
|
||||
* - `root` root directory for relative filenames
|
||||
*
|
||||
* Examples:
|
||||
*
|
||||
* The following example illustrates how `res.sendfile()` may
|
||||
* be used as an alternative for the `static()` middleware for
|
||||
* dynamic situations. The code backing `res.sendfile()` is actually
|
||||
* the same code, so HTTP cache support etc is identical.
|
||||
*
|
||||
* app.get('/user/:uid/photos/:file', function(req, res){
|
||||
* var uid = req.params.uid
|
||||
* , file = req.params.file;
|
||||
*
|
||||
* req.user.mayViewFilesFrom(uid, function(yes){
|
||||
* if (yes) {
|
||||
* res.sendfile('/uploads/' + uid + '/' + file);
|
||||
* } else {
|
||||
* res.send(403, 'Sorry! you cant see that.');
|
||||
* }
|
||||
* });
|
||||
* });
|
||||
*
|
||||
* @param {String} path
|
||||
* @param {Object|Function} options or fn
|
||||
* @param {Function} fn
|
||||
* @api public
|
||||
*/
|
||||
|
||||
res.sendfile = function(path, options, fn){
|
||||
var self = this
|
||||
, req = self.req
|
||||
, next = this.req.next
|
||||
, options = options || {}
|
||||
, done;
|
||||
|
||||
// support function as second arg
|
||||
if ('function' == typeof options) {
|
||||
fn = options;
|
||||
options = {};
|
||||
}
|
||||
|
||||
// socket errors
|
||||
req.socket.on('error', error);
|
||||
|
||||
// errors
|
||||
function error(err) {
|
||||
if (done) return;
|
||||
done = true;
|
||||
|
||||
// clean up
|
||||
cleanup();
|
||||
if (!self.headerSent) self.removeHeader('Content-Disposition');
|
||||
|
||||
// callback available
|
||||
if (fn) return fn(err);
|
||||
|
||||
// list in limbo if there's no callback
|
||||
if (self.headerSent) return;
|
||||
|
||||
// delegate
|
||||
next(err);
|
||||
}
|
||||
|
||||
// streaming
|
||||
function stream() {
|
||||
if (done) return;
|
||||
cleanup();
|
||||
if (fn) self.on('finish', fn);
|
||||
}
|
||||
|
||||
// cleanup
|
||||
function cleanup() {
|
||||
req.socket.removeListener('error', error);
|
||||
}
|
||||
|
||||
// transfer
|
||||
var file = send(req, path);
|
||||
if (options.root) file.root(options.root);
|
||||
file.maxage(options.maxAge || 0);
|
||||
file.on('error', error);
|
||||
file.on('directory', next);
|
||||
file.on('stream', stream);
|
||||
file.pipe(this);
|
||||
this.on('finish', cleanup);
|
||||
};
|
||||
|
||||
/**
|
||||
* Transfer the file at the given `path` as an attachment.
|
||||
*
|
||||
* Optionally providing an alternate attachment `filename`,
|
||||
* and optional callback `fn(err)`. The callback is invoked
|
||||
* when the data transfer is complete, or when an error has
|
||||
* ocurred. Be sure to check `res.headerSent` if you plan to respond.
|
||||
*
|
||||
* This method uses `res.sendfile()`.
|
||||
*
|
||||
* @param {String} path
|
||||
* @param {String|Function} filename or fn
|
||||
* @param {Function} fn
|
||||
* @api public
|
||||
*/
|
||||
|
||||
res.download = function(path, filename, fn){
|
||||
// support function as second arg
|
||||
if ('function' == typeof filename) {
|
||||
fn = filename;
|
||||
filename = null;
|
||||
}
|
||||
|
||||
filename = filename || path;
|
||||
this.set('Content-Disposition', 'attachment; filename="' + basename(filename) + '"');
|
||||
return this.sendfile(path, fn);
|
||||
};
|
||||
|
||||
/**
|
||||
* Set _Content-Type_ response header with `type` through `mime.lookup()`
|
||||
* when it does not contain "/", or set the Content-Type to `type` otherwise.
|
||||
*
|
||||
* Examples:
|
||||
*
|
||||
* res.type('.html');
|
||||
* res.type('html');
|
||||
* res.type('json');
|
||||
* res.type('application/json');
|
||||
* res.type('png');
|
||||
*
|
||||
* @param {String} type
|
||||
* @return {ServerResponse} for chaining
|
||||
* @api public
|
||||
*/
|
||||
|
||||
res.contentType =
|
||||
res.type = function(type){
|
||||
return this.set('Content-Type', ~type.indexOf('/')
|
||||
? type
|
||||
: mime.lookup(type));
|
||||
};
|
||||
|
||||
/**
|
||||
* Respond to the Acceptable formats using an `obj`
|
||||
* of mime-type callbacks.
|
||||
*
|
||||
* This method uses `req.accepted`, an array of
|
||||
* acceptable types ordered by their quality values.
|
||||
* When "Accept" is not present the _first_ callback
|
||||
* is invoked, otherwise the first match is used. When
|
||||
* no match is performed the server responds with
|
||||
* 406 "Not Acceptable".
|
||||
*
|
||||
* Content-Type is set for you, however if you choose
|
||||
* you may alter this within the callback using `res.type()`
|
||||
* or `res.set('Content-Type', ...)`.
|
||||
*
|
||||
* res.format({
|
||||
* 'text/plain': function(){
|
||||
* res.send('hey');
|
||||
* },
|
||||
*
|
||||
* 'text/html': function(){
|
||||
* res.send('<p>hey</p>');
|
||||
* },
|
||||
*
|
||||
* 'appliation/json': function(){
|
||||
* res.send({ message: 'hey' });
|
||||
* }
|
||||
* });
|
||||
*
|
||||
* In addition to canonicalized MIME types you may
|
||||
* also use extnames mapped to these types:
|
||||
*
|
||||
* res.format({
|
||||
* text: function(){
|
||||
* res.send('hey');
|
||||
* },
|
||||
*
|
||||
* html: function(){
|
||||
* res.send('<p>hey</p>');
|
||||
* },
|
||||
*
|
||||
* json: function(){
|
||||
* res.send({ message: 'hey' });
|
||||
* }
|
||||
* });
|
||||
*
|
||||
* By default Express passes an `Error`
|
||||
* with a `.status` of 406 to `next(err)`
|
||||
* if a match is not made. If you provide
|
||||
* a `.default` callback it will be invoked
|
||||
* instead.
|
||||
*
|
||||
* @param {Object} obj
|
||||
* @return {ServerResponse} for chaining
|
||||
* @api public
|
||||
*/
|
||||
|
||||
res.format = function(obj){
|
||||
var req = this.req
|
||||
, next = req.next;
|
||||
|
||||
var fn = obj.default;
|
||||
if (fn) delete obj.default;
|
||||
var keys = Object.keys(obj);
|
||||
|
||||
var key = req.accepts(keys);
|
||||
|
||||
this.set('Vary', 'Accept');
|
||||
|
||||
if (key) {
|
||||
this.set('Content-Type', normalizeType(key).value);
|
||||
obj[key](req, this, next);
|
||||
} else if (fn) {
|
||||
fn();
|
||||
} else {
|
||||
var err = new Error('Not Acceptable');
|
||||
err.status = 406;
|
||||
err.types = normalizeTypes(keys).map(function(o){ return o.value });
|
||||
next(err);
|
||||
}
|
||||
|
||||
return this;
|
||||
};
|
||||
|
||||
/**
|
||||
* Set _Content-Disposition_ header to _attachment_ with optional `filename`.
|
||||
*
|
||||
* @param {String} filename
|
||||
* @return {ServerResponse}
|
||||
* @api public
|
||||
*/
|
||||
|
||||
res.attachment = function(filename){
|
||||
if (filename) this.type(extname(filename));
|
||||
this.set('Content-Disposition', filename
|
||||
? 'attachment; filename="' + basename(filename) + '"'
|
||||
: 'attachment');
|
||||
return this;
|
||||
};
|
||||
|
||||
/**
|
||||
* Set header `field` to `val`, or pass
|
||||
* an object of header fields.
|
||||
*
|
||||
* Examples:
|
||||
*
|
||||
* res.set('Foo', ['bar', 'baz']);
|
||||
* res.set('Accept', 'application/json');
|
||||
* res.set({ Accept: 'text/plain', 'X-API-Key': 'tobi' });
|
||||
*
|
||||
* Aliased as `res.header()`.
|
||||
*
|
||||
* @param {String|Object|Array} field
|
||||
* @param {String} val
|
||||
* @return {ServerResponse} for chaining
|
||||
* @api public
|
||||
*/
|
||||
|
||||
res.set =
|
||||
res.header = function(field, val){
|
||||
if (2 == arguments.length) {
|
||||
if (Array.isArray(val)) val = val.map(String);
|
||||
else val = String(val);
|
||||
this.setHeader(field, val);
|
||||
} else {
|
||||
for (var key in field) {
|
||||
this.set(key, field[key]);
|
||||
}
|
||||
}
|
||||
return this;
|
||||
};
|
||||
|
||||
/**
|
||||
* Get value for header `field`.
|
||||
*
|
||||
* @param {String} field
|
||||
* @return {String}
|
||||
* @api public
|
||||
*/
|
||||
|
||||
res.get = function(field){
|
||||
return this.getHeader(field);
|
||||
};
|
||||
|
||||
/**
|
||||
* Clear cookie `name`.
|
||||
*
|
||||
* @param {String} name
|
||||
* @param {Object} options
|
||||
* @param {ServerResponse} for chaining
|
||||
* @api public
|
||||
*/
|
||||
|
||||
res.clearCookie = function(name, options){
|
||||
var opts = { expires: new Date(1), path: '/' };
|
||||
return this.cookie(name, '', options
|
||||
? utils.merge(opts, options)
|
||||
: opts);
|
||||
};
|
||||
|
||||
/**
|
||||
* Set cookie `name` to `val`, with the given `options`.
|
||||
*
|
||||
* Options:
|
||||
*
|
||||
* - `maxAge` max-age in milliseconds, converted to `expires`
|
||||
* - `signed` sign the cookie
|
||||
* - `path` defaults to "/"
|
||||
*
|
||||
* Examples:
|
||||
*
|
||||
* // "Remember Me" for 15 minutes
|
||||
* res.cookie('rememberme', '1', { expires: new Date(Date.now() + 900000), httpOnly: true });
|
||||
*
|
||||
* // save as above
|
||||
* res.cookie('rememberme', '1', { maxAge: 900000, httpOnly: true })
|
||||
*
|
||||
* @param {String} name
|
||||
* @param {String|Object} val
|
||||
* @param {Options} options
|
||||
* @api public
|
||||
*/
|
||||
|
||||
res.cookie = function(name, val, options){
|
||||
options = utils.merge({}, options);
|
||||
var secret = this.req.secret;
|
||||
var signed = options.signed;
|
||||
if (signed && !secret) throw new Error('connect.cookieParser("secret") required for signed cookies');
|
||||
if ('object' == typeof val) val = 'j:' + JSON.stringify(val);
|
||||
if (signed) val = 's:' + sign(val, secret);
|
||||
if ('maxAge' in options) {
|
||||
options.expires = new Date(Date.now() + options.maxAge);
|
||||
options.maxAge /= 1000;
|
||||
}
|
||||
if (null == options.path) options.path = '/';
|
||||
this.set('Set-Cookie', cookie.serialize(name, String(val), options));
|
||||
return this;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Set the location header to `url`.
|
||||
*
|
||||
* The given `url` can also be the name of a mapped url, for
|
||||
* example by default express supports "back" which redirects
|
||||
* to the _Referrer_ or _Referer_ headers or "/".
|
||||
*
|
||||
* Examples:
|
||||
*
|
||||
* res.location('/foo/bar').;
|
||||
* res.location('http://example.com');
|
||||
* res.location('../login'); // /blog/post/1 -> /blog/login
|
||||
*
|
||||
* Mounting:
|
||||
*
|
||||
* When an application is mounted and `res.location()`
|
||||
* is given a path that does _not_ lead with "/" it becomes
|
||||
* relative to the mount-point. For example if the application
|
||||
* is mounted at "/blog", the following would become "/blog/login".
|
||||
*
|
||||
* res.location('login');
|
||||
*
|
||||
* While the leading slash would result in a location of "/login":
|
||||
*
|
||||
* res.location('/login');
|
||||
*
|
||||
* @param {String} url
|
||||
* @api public
|
||||
*/
|
||||
|
||||
res.location = function(url){
|
||||
var app = this.app
|
||||
, req = this.req;
|
||||
|
||||
// setup redirect map
|
||||
var map = { back: req.get('Referrer') || '/' };
|
||||
|
||||
// perform redirect
|
||||
url = map[url] || url;
|
||||
|
||||
// relative
|
||||
if (!~url.indexOf('://') && 0 != url.indexOf('//')) {
|
||||
var path
|
||||
|
||||
// relative to path
|
||||
if ('.' == url[0]) {
|
||||
path = req.originalUrl.split('?')[0]
|
||||
url = path + ('/' == path[path.length - 1] ? '' : '/') + url;
|
||||
// relative to mount-point
|
||||
} else if ('/' != url[0]) {
|
||||
path = app.path();
|
||||
url = path + '/' + url;
|
||||
}
|
||||
}
|
||||
|
||||
// Respond
|
||||
this.set('Location', url);
|
||||
return this;
|
||||
};
|
||||
|
||||
/**
|
||||
* Redirect to the given `url` with optional response `status`
|
||||
* defaulting to 302.
|
||||
*
|
||||
* The resulting `url` is determined by `res.location()`, so
|
||||
* it will play nicely with mounted apps, relative paths,
|
||||
* `"back"` etc.
|
||||
*
|
||||
* Examples:
|
||||
*
|
||||
* res.redirect('/foo/bar');
|
||||
* res.redirect('http://example.com');
|
||||
* res.redirect(301, 'http://example.com');
|
||||
* res.redirect('http://example.com', 301);
|
||||
* res.redirect('../login'); // /blog/post/1 -> /blog/login
|
||||
*
|
||||
* @param {String} url
|
||||
* @param {Number} code
|
||||
* @api public
|
||||
*/
|
||||
|
||||
res.redirect = function(url){
|
||||
var app = this.app
|
||||
, head = 'HEAD' == this.req.method
|
||||
, status = 302
|
||||
, body;
|
||||
|
||||
// allow status / url
|
||||
if (2 == arguments.length) {
|
||||
if ('number' == typeof url) {
|
||||
status = url;
|
||||
url = arguments[1];
|
||||
} else {
|
||||
status = arguments[1];
|
||||
}
|
||||
}
|
||||
|
||||
// Set location header
|
||||
this.location(url);
|
||||
url = this.get('Location');
|
||||
|
||||
// Support text/{plain,html} by default
|
||||
this.format({
|
||||
text: function(){
|
||||
body = statusCodes[status] + '. Redirecting to ' + encodeURI(url);
|
||||
},
|
||||
|
||||
html: function(){
|
||||
var u = utils.escape(url);
|
||||
body = '<p>' + statusCodes[status] + '. Redirecting to <a href="' + u + '">' + u + '</a></p>';
|
||||
},
|
||||
|
||||
default: function(){
|
||||
body = '';
|
||||
}
|
||||
});
|
||||
|
||||
// Respond
|
||||
this.statusCode = status;
|
||||
this.set('Content-Length', Buffer.byteLength(body));
|
||||
this.end(head ? null : body);
|
||||
};
|
||||
|
||||
/**
|
||||
* Render `view` with the given `options` and optional callback `fn`.
|
||||
* When a callback function is given a response will _not_ be made
|
||||
* automatically, otherwise a response of _200_ and _text/html_ is given.
|
||||
*
|
||||
* Options:
|
||||
*
|
||||
* - `cache` boolean hinting to the engine it should cache
|
||||
* - `filename` filename of the view being rendered
|
||||
*
|
||||
* @param {String} view
|
||||
* @param {Object|Function} options or callback function
|
||||
* @param {Function} fn
|
||||
* @api public
|
||||
*/
|
||||
|
||||
res.render = function(view, options, fn){
|
||||
var self = this
|
||||
, options = options || {}
|
||||
, req = this.req
|
||||
, app = req.app;
|
||||
|
||||
// support callback function as second arg
|
||||
if ('function' == typeof options) {
|
||||
fn = options, options = {};
|
||||
}
|
||||
|
||||
// merge res.locals
|
||||
options._locals = self.locals;
|
||||
|
||||
// default callback to respond
|
||||
fn = fn || function(err, str){
|
||||
if (err) return req.next(err);
|
||||
self.send(str);
|
||||
};
|
||||
|
||||
// render
|
||||
app.render(view, options, fn);
|
||||
};
|
|
@ -1,273 +0,0 @@
|
|||
/**
|
||||
* Module dependencies.
|
||||
*/
|
||||
|
||||
var Route = require('./route')
|
||||
, utils = require('../utils')
|
||||
, methods = require('methods')
|
||||
, debug = require('debug')('express:router')
|
||||
, parse = require('connect').utils.parseUrl;
|
||||
|
||||
/**
|
||||
* Expose `Router` constructor.
|
||||
*/
|
||||
|
||||
exports = module.exports = Router;
|
||||
|
||||
/**
|
||||
* Initialize a new `Router` with the given `options`.
|
||||
*
|
||||
* @param {Object} options
|
||||
* @api private
|
||||
*/
|
||||
|
||||
function Router(options) {
|
||||
options = options || {};
|
||||
var self = this;
|
||||
this.map = {};
|
||||
this.params = {};
|
||||
this._params = [];
|
||||
this.caseSensitive = options.caseSensitive;
|
||||
this.strict = options.strict;
|
||||
this.middleware = function router(req, res, next){
|
||||
self._dispatch(req, res, next);
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Register a param callback `fn` for the given `name`.
|
||||
*
|
||||
* @param {String|Function} name
|
||||
* @param {Function} fn
|
||||
* @return {Router} for chaining
|
||||
* @api public
|
||||
*/
|
||||
|
||||
Router.prototype.param = function(name, fn){
|
||||
// param logic
|
||||
if ('function' == typeof name) {
|
||||
this._params.push(name);
|
||||
return;
|
||||
}
|
||||
|
||||
// apply param functions
|
||||
var params = this._params
|
||||
, len = params.length
|
||||
, ret;
|
||||
|
||||
for (var i = 0; i < len; ++i) {
|
||||
if (ret = params[i](name, fn)) {
|
||||
fn = ret;
|
||||
}
|
||||
}
|
||||
|
||||
// ensure we end up with a
|
||||
// middleware function
|
||||
if ('function' != typeof fn) {
|
||||
throw new Error('invalid param() call for ' + name + ', got ' + fn);
|
||||
}
|
||||
|
||||
(this.params[name] = this.params[name] || []).push(fn);
|
||||
return this;
|
||||
};
|
||||
|
||||
/**
|
||||
* Route dispatcher aka the route "middleware".
|
||||
*
|
||||
* @param {IncomingMessage} req
|
||||
* @param {ServerResponse} res
|
||||
* @param {Function} next
|
||||
* @api private
|
||||
*/
|
||||
|
||||
Router.prototype._dispatch = function(req, res, next){
|
||||
var params = this.params
|
||||
, self = this;
|
||||
|
||||
debug('dispatching %s %s (%s)', req.method, req.url, req.originalUrl);
|
||||
|
||||
// route dispatch
|
||||
(function pass(i, err){
|
||||
var paramCallbacks
|
||||
, paramIndex = 0
|
||||
, paramVal
|
||||
, route
|
||||
, keys
|
||||
, key;
|
||||
|
||||
// match next route
|
||||
function nextRoute(err) {
|
||||
pass(req._route_index + 1, err);
|
||||
}
|
||||
|
||||
// match route
|
||||
req.route = route = self.matchRequest(req, i);
|
||||
|
||||
// no route
|
||||
if (!route) return next(err);
|
||||
debug('matched %s %s', route.method, route.path);
|
||||
|
||||
// we have a route
|
||||
// start at param 0
|
||||
req.params = route.params;
|
||||
keys = route.keys;
|
||||
i = 0;
|
||||
|
||||
// param callbacks
|
||||
function param(err) {
|
||||
paramIndex = 0;
|
||||
key = keys[i++];
|
||||
paramVal = key && req.params[key.name];
|
||||
paramCallbacks = key && params[key.name];
|
||||
|
||||
try {
|
||||
if ('route' == err) {
|
||||
nextRoute();
|
||||
} else if (err) {
|
||||
i = 0;
|
||||
callbacks(err);
|
||||
} else if (paramCallbacks && undefined !== paramVal) {
|
||||
paramCallback();
|
||||
} else if (key) {
|
||||
param();
|
||||
} else {
|
||||
i = 0;
|
||||
callbacks();
|
||||
}
|
||||
} catch (err) {
|
||||
param(err);
|
||||
}
|
||||
};
|
||||
|
||||
param(err);
|
||||
|
||||
// single param callbacks
|
||||
function paramCallback(err) {
|
||||
var fn = paramCallbacks[paramIndex++];
|
||||
if (err || !fn) return param(err);
|
||||
fn(req, res, paramCallback, paramVal, key.name);
|
||||
}
|
||||
|
||||
// invoke route callbacks
|
||||
function callbacks(err) {
|
||||
var fn = route.callbacks[i++];
|
||||
try {
|
||||
if ('route' == err) {
|
||||
nextRoute();
|
||||
} else if (err && fn) {
|
||||
if (fn.length < 4) return callbacks(err);
|
||||
fn(err, req, res, callbacks);
|
||||
} else if (fn) {
|
||||
if (fn.length < 4) return fn(req, res, callbacks);
|
||||
callbacks();
|
||||
} else {
|
||||
nextRoute(err);
|
||||
}
|
||||
} catch (err) {
|
||||
callbacks(err);
|
||||
}
|
||||
}
|
||||
})(0);
|
||||
};
|
||||
|
||||
/**
|
||||
* Attempt to match a route for `req`
|
||||
* with optional starting index of `i`
|
||||
* defaulting to 0.
|
||||
*
|
||||
* @param {IncomingMessage} req
|
||||
* @param {Number} i
|
||||
* @return {Route}
|
||||
* @api private
|
||||
*/
|
||||
|
||||
Router.prototype.matchRequest = function(req, i, head){
|
||||
var method = req.method.toLowerCase()
|
||||
, url = parse(req)
|
||||
, path = url.pathname
|
||||
, routes = this.map
|
||||
, i = i || 0
|
||||
, route;
|
||||
|
||||
// HEAD support
|
||||
if (!head && 'head' == method) {
|
||||
route = this.matchRequest(req, i, true);
|
||||
if (route) return route;
|
||||
method = 'get';
|
||||
}
|
||||
|
||||
// routes for this method
|
||||
if (routes = routes[method]) {
|
||||
|
||||
// matching routes
|
||||
for (var len = routes.length; i < len; ++i) {
|
||||
route = routes[i];
|
||||
if (route.match(path)) {
|
||||
req._route_index = i;
|
||||
return route;
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Attempt to match a route for `method`
|
||||
* and `url` with optional starting
|
||||
* index of `i` defaulting to 0.
|
||||
*
|
||||
* @param {String} method
|
||||
* @param {String} url
|
||||
* @param {Number} i
|
||||
* @return {Route}
|
||||
* @api private
|
||||
*/
|
||||
|
||||
Router.prototype.match = function(method, url, i, head){
|
||||
var req = { method: method, url: url };
|
||||
return this.matchRequest(req, i, head);
|
||||
};
|
||||
|
||||
/**
|
||||
* Route `method`, `path`, and one or more callbacks.
|
||||
*
|
||||
* @param {String} method
|
||||
* @param {String} path
|
||||
* @param {Function} callback...
|
||||
* @return {Router} for chaining
|
||||
* @api private
|
||||
*/
|
||||
|
||||
Router.prototype.route = function(method, path, callbacks){
|
||||
var method = method.toLowerCase()
|
||||
, callbacks = utils.flatten([].slice.call(arguments, 2));
|
||||
|
||||
// ensure path was given
|
||||
if (!path) throw new Error('Router#' + method + '() requires a path');
|
||||
|
||||
// ensure all callbacks are functions
|
||||
callbacks.forEach(function(fn, i){
|
||||
if ('function' == typeof fn) return;
|
||||
var type = {}.toString.call(fn);
|
||||
var msg = '.' + method + '() requires callback functions but got a ' + type;
|
||||
throw new Error(msg);
|
||||
});
|
||||
|
||||
// create the route
|
||||
debug('defined %s %s', method, path);
|
||||
var route = new Route(method, path, callbacks, {
|
||||
sensitive: this.caseSensitive,
|
||||
strict: this.strict
|
||||
});
|
||||
|
||||
// add it
|
||||
(this.map[method] = this.map[method] || []).push(route);
|
||||
return this;
|
||||
};
|
||||
|
||||
methods.forEach(function(method){
|
||||
Router.prototype[method] = function(path){
|
||||
var args = [method].concat([].slice.call(arguments));
|
||||
this.route.apply(this, args);
|
||||
return this;
|
||||
};
|
||||
});
|
|
@ -1,72 +0,0 @@
|
|||
|
||||
/**
|
||||
* Module dependencies.
|
||||
*/
|
||||
|
||||
var utils = require('../utils');
|
||||
|
||||
/**
|
||||
* Expose `Route`.
|
||||
*/
|
||||
|
||||
module.exports = Route;
|
||||
|
||||
/**
|
||||
* Initialize `Route` with the given HTTP `method`, `path`,
|
||||
* and an array of `callbacks` and `options`.
|
||||
*
|
||||
* Options:
|
||||
*
|
||||
* - `sensitive` enable case-sensitive routes
|
||||
* - `strict` enable strict matching for trailing slashes
|
||||
*
|
||||
* @param {String} method
|
||||
* @param {String} path
|
||||
* @param {Array} callbacks
|
||||
* @param {Object} options.
|
||||
* @api private
|
||||
*/
|
||||
|
||||
function Route(method, path, callbacks, options) {
|
||||
options = options || {};
|
||||
this.path = path;
|
||||
this.method = method;
|
||||
this.callbacks = callbacks;
|
||||
this.regexp = utils.pathRegexp(path
|
||||
, this.keys = []
|
||||
, options.sensitive
|
||||
, options.strict);
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if this route matches `path`, if so
|
||||
* populate `.params`.
|
||||
*
|
||||
* @param {String} path
|
||||
* @return {Boolean}
|
||||
* @api private
|
||||
*/
|
||||
|
||||
Route.prototype.match = function(path){
|
||||
var keys = this.keys
|
||||
, params = this.params = []
|
||||
, m = this.regexp.exec(path);
|
||||
|
||||
if (!m) return false;
|
||||
|
||||
for (var i = 1, len = m.length; i < len; ++i) {
|
||||
var key = keys[i - 1];
|
||||
|
||||
var val = 'string' == typeof m[i]
|
||||
? decodeURIComponent(m[i])
|
||||
: m[i];
|
||||
|
||||
if (key) {
|
||||
params[key.name] = val;
|
||||
} else {
|
||||
params.push(val);
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
};
|
|
@ -1,302 +0,0 @@
|
|||
|
||||
/**
|
||||
* Module dependencies.
|
||||
*/
|
||||
|
||||
var mime = require('connect').mime
|
||||
, crc32 = require('buffer-crc32');
|
||||
|
||||
/**
|
||||
* Return ETag for `body`.
|
||||
*
|
||||
* @param {String|Buffer} body
|
||||
* @return {String}
|
||||
* @api private
|
||||
*/
|
||||
|
||||
exports.etag = function(body){
|
||||
return '"' + crc32.signed(body) + '"';
|
||||
};
|
||||
|
||||
/**
|
||||
* Make `locals()` bound to the given `obj`.
|
||||
*
|
||||
* This is used for `app.locals` and `res.locals`.
|
||||
*
|
||||
* @param {Object} obj
|
||||
* @return {Function}
|
||||
* @api private
|
||||
*/
|
||||
|
||||
exports.locals = function(obj){
|
||||
function locals(obj){
|
||||
for (var key in obj) locals[key] = obj[key];
|
||||
return obj;
|
||||
};
|
||||
|
||||
return locals;
|
||||
};
|
||||
|
||||
/**
|
||||
* Check if `path` looks absolute.
|
||||
*
|
||||
* @param {String} path
|
||||
* @return {Boolean}
|
||||
* @api private
|
||||
*/
|
||||
|
||||
exports.isAbsolute = function(path){
|
||||
if ('/' == path[0]) return true;
|
||||
if (':' == path[1] && '\\' == path[2]) return true;
|
||||
};
|
||||
|
||||
/**
|
||||
* Flatten the given `arr`.
|
||||
*
|
||||
* @param {Array} arr
|
||||
* @return {Array}
|
||||
* @api private
|
||||
*/
|
||||
|
||||
exports.flatten = function(arr, ret){
|
||||
var ret = ret || []
|
||||
, len = arr.length;
|
||||
for (var i = 0; i < len; ++i) {
|
||||
if (Array.isArray(arr[i])) {
|
||||
exports.flatten(arr[i], ret);
|
||||
} else {
|
||||
ret.push(arr[i]);
|
||||
}
|
||||
}
|
||||
return ret;
|
||||
};
|
||||
|
||||
/**
|
||||
* Normalize the given `type`, for example "html" becomes "text/html".
|
||||
*
|
||||
* @param {String} type
|
||||
* @return {Object}
|
||||
* @api private
|
||||
*/
|
||||
|
||||
exports.normalizeType = function(type){
|
||||
return ~type.indexOf('/')
|
||||
? acceptParams(type)
|
||||
: { value: mime.lookup(type), params: {} };
|
||||
};
|
||||
|
||||
/**
|
||||
* Normalize `types`, for example "html" becomes "text/html".
|
||||
*
|
||||
* @param {Array} types
|
||||
* @return {Array}
|
||||
* @api private
|
||||
*/
|
||||
|
||||
exports.normalizeTypes = function(types){
|
||||
var ret = [];
|
||||
|
||||
for (var i = 0; i < types.length; ++i) {
|
||||
ret.push(exports.normalizeType(types[i]));
|
||||
}
|
||||
|
||||
return ret;
|
||||
};
|
||||
|
||||
/**
|
||||
* Return the acceptable type in `types`, if any.
|
||||
*
|
||||
* @param {Array} types
|
||||
* @param {String} str
|
||||
* @return {String}
|
||||
* @api private
|
||||
*/
|
||||
|
||||
exports.acceptsArray = function(types, str){
|
||||
// accept anything when Accept is not present
|
||||
if (!str) return types[0];
|
||||
|
||||
// parse
|
||||
var accepted = exports.parseAccept(str)
|
||||
, normalized = exports.normalizeTypes(types)
|
||||
, len = accepted.length;
|
||||
|
||||
for (var i = 0; i < len; ++i) {
|
||||
for (var j = 0, jlen = types.length; j < jlen; ++j) {
|
||||
if (exports.accept(normalized[j], accepted[i])) {
|
||||
return types[j];
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Check if `type(s)` are acceptable based on
|
||||
* the given `str`.
|
||||
*
|
||||
* @param {String|Array} type(s)
|
||||
* @param {String} str
|
||||
* @return {Boolean|String}
|
||||
* @api private
|
||||
*/
|
||||
|
||||
exports.accepts = function(type, str){
|
||||
if ('string' == typeof type) type = type.split(/ *, */);
|
||||
return exports.acceptsArray(type, str);
|
||||
};
|
||||
|
||||
/**
|
||||
* Check if `type` array is acceptable for `other`.
|
||||
*
|
||||
* @param {Object} type
|
||||
* @param {Object} other
|
||||
* @return {Boolean}
|
||||
* @api private
|
||||
*/
|
||||
|
||||
exports.accept = function(type, other){
|
||||
var t = type.value.split('/');
|
||||
return (t[0] == other.type || '*' == other.type)
|
||||
&& (t[1] == other.subtype || '*' == other.subtype)
|
||||
&& paramsEqual(type.params, other.params);
|
||||
};
|
||||
|
||||
/**
|
||||
* Check if accept params are equal.
|
||||
*
|
||||
* @param {Object} a
|
||||
* @param {Object} b
|
||||
* @return {Boolean}
|
||||
* @api private
|
||||
*/
|
||||
|
||||
function paramsEqual(a, b){
|
||||
return !Object.keys(a).some(function(k) {
|
||||
return a[k] != b[k];
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Parse accept `str`, returning
|
||||
* an array objects containing
|
||||
* `.type` and `.subtype` along
|
||||
* with the values provided by
|
||||
* `parseQuality()`.
|
||||
*
|
||||
* @param {Type} name
|
||||
* @return {Type}
|
||||
* @api private
|
||||
*/
|
||||
|
||||
exports.parseAccept = function(str){
|
||||
return exports
|
||||
.parseParams(str)
|
||||
.map(function(obj){
|
||||
var parts = obj.value.split('/');
|
||||
obj.type = parts[0];
|
||||
obj.subtype = parts[1];
|
||||
return obj;
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* Parse quality `str`, returning an
|
||||
* array of objects with `.value`,
|
||||
* `.quality` and optional `.params`
|
||||
*
|
||||
* @param {String} str
|
||||
* @return {Array}
|
||||
* @api private
|
||||
*/
|
||||
|
||||
exports.parseParams = function(str){
|
||||
return str
|
||||
.split(/ *, */)
|
||||
.map(acceptParams)
|
||||
.filter(function(obj){
|
||||
return obj.quality;
|
||||
})
|
||||
.sort(function(a, b){
|
||||
return b.quality - a.quality;
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* Parse accept params `str` returning an
|
||||
* object with `.value`, `.quality` and `.params`.
|
||||
*
|
||||
* @param {String} str
|
||||
* @return {Object}
|
||||
* @api private
|
||||
*/
|
||||
|
||||
function acceptParams(str) {
|
||||
var parts = str.split(/ *; */);
|
||||
var ret = { value: parts[0], quality: 1, params: {} };
|
||||
|
||||
for (var i = 1; i < parts.length; ++i) {
|
||||
var pms = parts[i].split(/ *= */);
|
||||
if ('q' == pms[0]) {
|
||||
ret.quality = parseFloat(pms[1]);
|
||||
} else {
|
||||
ret.params[pms[0]] = pms[1];
|
||||
}
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* Escape special characters in the given string of html.
|
||||
*
|
||||
* @param {String} html
|
||||
* @return {String}
|
||||
* @api private
|
||||
*/
|
||||
|
||||
exports.escape = function(html) {
|
||||
return String(html)
|
||||
.replace(/&/g, '&')
|
||||
.replace(/"/g, '"')
|
||||
.replace(/</g, '<')
|
||||
.replace(/>/g, '>');
|
||||
};
|
||||
|
||||
/**
|
||||
* Normalize the given path string,
|
||||
* returning a regular expression.
|
||||
*
|
||||
* An empty array should be passed,
|
||||
* which will contain the placeholder
|
||||
* key names. For example "/user/:id" will
|
||||
* then contain ["id"].
|
||||
*
|
||||
* @param {String|RegExp|Array} path
|
||||
* @param {Array} keys
|
||||
* @param {Boolean} sensitive
|
||||
* @param {Boolean} strict
|
||||
* @return {RegExp}
|
||||
* @api private
|
||||
*/
|
||||
|
||||
exports.pathRegexp = function(path, keys, sensitive, strict) {
|
||||
if (path instanceof RegExp) return path;
|
||||
if (Array.isArray(path)) path = '(' + path.join('|') + ')';
|
||||
path = path
|
||||
.concat(strict ? '' : '/?')
|
||||
.replace(/\/\(/g, '(?:/')
|
||||
.replace(/(\/)?(\.)?:(\w+)(?:(\(.*?\)))?(\?)?(\*)?/g, function(_, slash, format, key, capture, optional, star){
|
||||
keys.push({ name: key, optional: !! optional });
|
||||
slash = slash || '';
|
||||
return ''
|
||||
+ (optional ? '' : slash)
|
||||
+ '(?:'
|
||||
+ (optional ? slash : '')
|
||||
+ (format || '') + (capture || (format && '([^/.]+?)' || '([^/]+?)')) + ')'
|
||||
+ (optional || '')
|
||||
+ (star ? '(/*)?' : '');
|
||||
})
|
||||
.replace(/([\/.])/g, '\\$1')
|
||||
.replace(/\*/g, '(.*)');
|
||||
return new RegExp('^' + path + '$', sensitive ? '' : 'i');
|
||||
}
|
|
@ -1,76 +0,0 @@
|
|||
/**
|
||||
* Module dependencies.
|
||||
*/
|
||||
|
||||
var path = require('path')
|
||||
, fs = require('fs')
|
||||
, utils = require('./utils')
|
||||
, dirname = path.dirname
|
||||
, basename = path.basename
|
||||
, extname = path.extname
|
||||
, exists = fs.existsSync || path.existsSync
|
||||
, join = path.join;
|
||||
|
||||
/**
|
||||
* Expose `View`.
|
||||
*/
|
||||
|
||||
module.exports = View;
|
||||
|
||||
/**
|
||||
* Initialize a new `View` with the given `name`.
|
||||
*
|
||||
* Options:
|
||||
*
|
||||
* - `defaultEngine` the default template engine name
|
||||
* - `engines` template engine require() cache
|
||||
* - `root` root path for view lookup
|
||||
*
|
||||
* @param {String} name
|
||||
* @param {Object} options
|
||||
* @api private
|
||||
*/
|
||||
|
||||
function View(name, options) {
|
||||
options = options || {};
|
||||
this.name = name;
|
||||
this.root = options.root;
|
||||
var engines = options.engines;
|
||||
this.defaultEngine = options.defaultEngine;
|
||||
var ext = this.ext = extname(name);
|
||||
if (!ext) name += (ext = this.ext = ('.' != this.defaultEngine[0] ? '.' : '') + this.defaultEngine);
|
||||
this.engine = engines[ext] || (engines[ext] = require(ext.slice(1)).__express);
|
||||
this.path = this.lookup(name);
|
||||
}
|
||||
|
||||
/**
|
||||
* Lookup view by the given `path`
|
||||
*
|
||||
* @param {String} path
|
||||
* @return {String}
|
||||
* @api private
|
||||
*/
|
||||
|
||||
View.prototype.lookup = function(path){
|
||||
var ext = this.ext;
|
||||
|
||||
// <path>.<engine>
|
||||
if (!utils.isAbsolute(path)) path = join(this.root, path);
|
||||
if (exists(path)) return path;
|
||||
|
||||
// <path>/index.<engine>
|
||||
path = join(dirname(path), basename(path, ext), 'index' + ext);
|
||||
if (exists(path)) return path;
|
||||
};
|
||||
|
||||
/**
|
||||
* Render with the given `options` and callback `fn(err, str)`.
|
||||
*
|
||||
* @param {Object} options
|
||||
* @param {Function} fn
|
||||
* @api private
|
||||
*/
|
||||
|
||||
View.prototype.render = function(options, fn){
|
||||
this.engine(this.path, options, fn);
|
||||
};
|
File diff suppressed because one or more lines are too long
|
@ -1,39 +0,0 @@
|
|||
|
||||
/**
|
||||
* Module dependencies.
|
||||
*/
|
||||
|
||||
var express = require('./')
|
||||
, app = express()
|
||||
|
||||
var users = ['foo', 'bar', 'baz'];
|
||||
|
||||
app.use(express.bodyParser());
|
||||
console.log(app.locals);
|
||||
|
||||
app.get('/api/users', function(req, res){
|
||||
res.send(users);
|
||||
});
|
||||
|
||||
app.del('/api/users', function(req, res){
|
||||
users = [];
|
||||
res.send(200);
|
||||
});
|
||||
|
||||
app.post('/api/users', function(req, res){
|
||||
users.push(req.body.name);
|
||||
res.send(201);
|
||||
});
|
||||
|
||||
app.get('/api/user/:id', function(req, res){
|
||||
var id = req.params.id;
|
||||
res.send(users[id]);
|
||||
});
|
||||
|
||||
app.use('/api', function(req, res, next){
|
||||
var err = new Error('Method Not Allowed');
|
||||
err.status = 405;
|
||||
});
|
||||
|
||||
app.listen(5555);
|
||||
console.log('listening on 5555');
|
|
@ -1 +0,0 @@
|
|||
/usr/local/lib/node_modules/sl-remoting
|
|
@ -9,6 +9,7 @@
|
|||
"debug": "latest",
|
||||
"express": "~3.1.1",
|
||||
"jugglingdb": "git+ssh://git@github.com:strongloop/jugglingdb.git",
|
||||
"jugglingdb-oracle": "git+ssh://git@github.com:strongloop/jugglingdb-oracle.git",
|
||||
"merge": "~1.1.0",
|
||||
"sl-module-loader": "git+ssh://git@github.com:strongloop/sl-module-loader.git",
|
||||
"sl-remoting": "git+ssh://git@github.com:strongloop/sl-remoting.git",
|
||||
|
|
Loading…
Reference in New Issue