init, just some testing
8
.gitignore
vendored
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
#################
|
||||||
|
## npm
|
||||||
|
#################
|
||||||
|
|
||||||
|
npm-debug.log
|
||||||
|
node_modules/
|
||||||
|
!/node_modules/
|
||||||
|
!src/node_modules/
|
||||||
59
RedisDB.js
Normal file
@@ -0,0 +1,59 @@
|
|||||||
|
(function(RedisDB) {
|
||||||
|
var PRODUCTION = false,
|
||||||
|
ERROR_LOGS = true,
|
||||||
|
|
||||||
|
redis = require('redis'),
|
||||||
|
db = redis.createClient();
|
||||||
|
|
||||||
|
// todo (holy cow): append,auth,bgrewriteaof,bgsave,bitcount,bitop,blpop,brpop,brpoplpush,client kill,client list,client getname,client setname,config get,config set,config resetstat,dbsize,debug object,debug segfault,decrby,del,discard,dump,echo,eval,evalsha,exec,exists,expire,expireat,flushall,flushdb,getbit,getrange,getset,hdel,hexists,hget,hgetall,hincrby,hincrbyfloat,hkeys,hlen,hmget,hmset,hset,hsetnx,hvals,incrby,incrbyfloat,info,keys,lastsave,lindex,linsert,llen,lpop,lpush,lpushx,lrange,lrem,lset,ltrim,mget,migrate,monitor,move,mset,msetnx,multi,object,persist,pexpire,pexpireat,ping,psetex,psubscribe,pttl,publish,punsubscribe,quit,randomkey,rename,renamenx,restore,rpop,rpoplpush,rpush,rpushx,sadd,save,scard,script exists,script flush,script kill,script load,sdiff,sdiffstore,select,setbit,setex,setnx,setrange,shutdown,sinter,sinterstore,sismember,slaveof,slowlog,smembers,smove,sort,spop,srandmember,srem,strlen,subscribe,sunion,sunionstore,sync,time,ttl,type,unsubscribe,unwatch,watch,zadd,zcard,zcount,zincrby,zinterstore,zrange,zrangebyscore,zrank,zrem,zremrangebyrank,zremrangebyscore,zrevrange,zrevrangebyscore,zrevrank,zscore,zunionstore
|
||||||
|
// done :^) get, set, incr, decr
|
||||||
|
|
||||||
|
function return_handler(error, data, callback, error_handler) {
|
||||||
|
if (error !== null) {
|
||||||
|
if (error_handler !== null) {
|
||||||
|
error_handler(error);
|
||||||
|
} else if (PRODUCTION === false) {
|
||||||
|
throw new Exception('RedisDB Error: ' + error);
|
||||||
|
} else if (ERROR_LOGS === true) {
|
||||||
|
console.log('RedisDB Error: ' + error);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
callback(data);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
RedisDB.set = function(key, value) {
|
||||||
|
db.set(key, value);
|
||||||
|
};
|
||||||
|
|
||||||
|
RedisDB.get = function(key, callback, error_handler) {
|
||||||
|
db.get(key, function(error, data) {
|
||||||
|
return_handler(error, data, callback, error_handler);
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
// Atomic Operations
|
||||||
|
RedisDB.incr = function(key, callback, error_handler) {
|
||||||
|
db.incr(key, function(error, data) {
|
||||||
|
if (callback) {
|
||||||
|
return_handler(error, data, callback, error_handler);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
RedisDB.decr = function(key) {
|
||||||
|
db.decr(key);
|
||||||
|
};
|
||||||
|
|
||||||
|
// Lists
|
||||||
|
RedisDB.lpush = function(key, item) {
|
||||||
|
db.lpush(key, item);
|
||||||
|
}
|
||||||
|
|
||||||
|
RedisDB.lrange = function(key, start, end, callback, error_handler) {
|
||||||
|
db.lrange(key, start, end, function(error, data) {
|
||||||
|
return_handler(error, data, callback, error_handler);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
}(exports));
|
||||||
26
app.js
Normal file
@@ -0,0 +1,26 @@
|
|||||||
|
var modules = {
|
||||||
|
user: require('./src/user.js'),
|
||||||
|
templates: require('./src/templates.js'),
|
||||||
|
webserver: require('./src/webserver.js'),
|
||||||
|
websockets: require('./src/websockets.js')
|
||||||
|
}
|
||||||
|
|
||||||
|
DEVELOPMENT = true;
|
||||||
|
|
||||||
|
|
||||||
|
global.configuration = {};
|
||||||
|
global.modules = modules;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
(function(config) {
|
||||||
|
config['ROOT_DIRECTORY'] = __dirname;
|
||||||
|
|
||||||
|
modules.templates.init();
|
||||||
|
modules.webserver.init();
|
||||||
|
modules.websockets.init();
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
}(global.configuration));
|
||||||
0
config.json
Normal file
1
node_modules/.bin/express
generated
vendored
Symbolic link
@@ -0,0 +1 @@
|
|||||||
|
../express/bin/express
|
||||||
12
node_modules/connect/.npmignore
generated
vendored
Normal file
@@ -0,0 +1,12 @@
|
|||||||
|
*.markdown
|
||||||
|
*.md
|
||||||
|
.git*
|
||||||
|
Makefile
|
||||||
|
benchmarks/
|
||||||
|
docs/
|
||||||
|
examples/
|
||||||
|
install.sh
|
||||||
|
support/
|
||||||
|
test/
|
||||||
|
.DS_Store
|
||||||
|
coverage.html
|
||||||
5
node_modules/connect/.travis.yml
generated
vendored
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
language: node_js
|
||||||
|
node_js:
|
||||||
|
- "0.6"
|
||||||
|
- "0.8"
|
||||||
|
- "0.10"
|
||||||
24
node_modules/connect/LICENSE
generated
vendored
Normal file
@@ -0,0 +1,24 @@
|
|||||||
|
(The MIT License)
|
||||||
|
|
||||||
|
Copyright (c) 2010 Sencha Inc.
|
||||||
|
Copyright (c) 2011 LearnBoost
|
||||||
|
Copyright (c) 2011 TJ Holowaychuk
|
||||||
|
|
||||||
|
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.
|
||||||
4
node_modules/connect/index.js
generated
vendored
Normal file
@@ -0,0 +1,4 @@
|
|||||||
|
|
||||||
|
module.exports = process.env.CONNECT_COV
|
||||||
|
? require('./lib-cov/connect')
|
||||||
|
: require('./lib/connect');
|
||||||
81
node_modules/connect/lib/cache.js
generated
vendored
Normal file
@@ -0,0 +1,81 @@
|
|||||||
|
|
||||||
|
/*!
|
||||||
|
* Connect - Cache
|
||||||
|
* Copyright(c) 2011 Sencha Inc.
|
||||||
|
* MIT Licensed
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Expose `Cache`.
|
||||||
|
*/
|
||||||
|
|
||||||
|
module.exports = Cache;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* LRU cache store.
|
||||||
|
*
|
||||||
|
* @param {Number} limit
|
||||||
|
* @api private
|
||||||
|
*/
|
||||||
|
|
||||||
|
function Cache(limit) {
|
||||||
|
this.store = {};
|
||||||
|
this.keys = [];
|
||||||
|
this.limit = limit;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Touch `key`, promoting the object.
|
||||||
|
*
|
||||||
|
* @param {String} key
|
||||||
|
* @param {Number} i
|
||||||
|
* @api private
|
||||||
|
*/
|
||||||
|
|
||||||
|
Cache.prototype.touch = function(key, i){
|
||||||
|
this.keys.splice(i,1);
|
||||||
|
this.keys.push(key);
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Remove `key`.
|
||||||
|
*
|
||||||
|
* @param {String} key
|
||||||
|
* @api private
|
||||||
|
*/
|
||||||
|
|
||||||
|
Cache.prototype.remove = function(key){
|
||||||
|
delete this.store[key];
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the object stored for `key`.
|
||||||
|
*
|
||||||
|
* @param {String} key
|
||||||
|
* @return {Array}
|
||||||
|
* @api private
|
||||||
|
*/
|
||||||
|
|
||||||
|
Cache.prototype.get = function(key){
|
||||||
|
return this.store[key];
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Add a cache `key`.
|
||||||
|
*
|
||||||
|
* @param {String} key
|
||||||
|
* @return {Array}
|
||||||
|
* @api private
|
||||||
|
*/
|
||||||
|
|
||||||
|
Cache.prototype.add = function(key){
|
||||||
|
// initialize store
|
||||||
|
var len = this.keys.push(key);
|
||||||
|
|
||||||
|
// limit reached, invalidate LRU
|
||||||
|
if (len > this.limit) this.remove(this.keys.shift());
|
||||||
|
|
||||||
|
var arr = this.store[key] = [];
|
||||||
|
arr.createdAt = new Date;
|
||||||
|
return arr;
|
||||||
|
};
|
||||||
92
node_modules/connect/lib/connect.js
generated
vendored
Normal file
@@ -0,0 +1,92 @@
|
|||||||
|
/*!
|
||||||
|
* Connect
|
||||||
|
* Copyright(c) 2010 Sencha Inc.
|
||||||
|
* Copyright(c) 2011 TJ Holowaychuk
|
||||||
|
* MIT Licensed
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Module dependencies.
|
||||||
|
*/
|
||||||
|
|
||||||
|
var EventEmitter = require('events').EventEmitter
|
||||||
|
, proto = require('./proto')
|
||||||
|
, utils = require('./utils')
|
||||||
|
, path = require('path')
|
||||||
|
, basename = path.basename
|
||||||
|
, fs = require('fs');
|
||||||
|
|
||||||
|
// node patches
|
||||||
|
|
||||||
|
require('./patch');
|
||||||
|
|
||||||
|
// expose createServer() as the module
|
||||||
|
|
||||||
|
exports = module.exports = createServer;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Framework version.
|
||||||
|
*/
|
||||||
|
|
||||||
|
exports.version = '2.7.6';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Expose mime module.
|
||||||
|
*/
|
||||||
|
|
||||||
|
exports.mime = require('./middleware/static').mime;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Expose the prototype.
|
||||||
|
*/
|
||||||
|
|
||||||
|
exports.proto = proto;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Auto-load middleware getters.
|
||||||
|
*/
|
||||||
|
|
||||||
|
exports.middleware = {};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Expose utilities.
|
||||||
|
*/
|
||||||
|
|
||||||
|
exports.utils = utils;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create a new connect server.
|
||||||
|
*
|
||||||
|
* @return {Function}
|
||||||
|
* @api public
|
||||||
|
*/
|
||||||
|
|
||||||
|
function createServer() {
|
||||||
|
function app(req, res, next){ app.handle(req, res, next); }
|
||||||
|
utils.merge(app, proto);
|
||||||
|
utils.merge(app, EventEmitter.prototype);
|
||||||
|
app.route = '/';
|
||||||
|
app.stack = [];
|
||||||
|
for (var i = 0; i < arguments.length; ++i) {
|
||||||
|
app.use(arguments[i]);
|
||||||
|
}
|
||||||
|
return app;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Support old `.createServer()` method.
|
||||||
|
*/
|
||||||
|
|
||||||
|
createServer.createServer = createServer;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Auto-load bundled middleware with getters.
|
||||||
|
*/
|
||||||
|
|
||||||
|
fs.readdirSync(__dirname + '/middleware').forEach(function(filename){
|
||||||
|
if (!/\.js$/.test(filename)) return;
|
||||||
|
var name = basename(filename, '.js');
|
||||||
|
function load(){ return require('./middleware/' + name); }
|
||||||
|
exports.middleware.__defineGetter__(name, load);
|
||||||
|
exports.__defineGetter__(name, load);
|
||||||
|
});
|
||||||
50
node_modules/connect/lib/index.js
generated
vendored
Normal file
@@ -0,0 +1,50 @@
|
|||||||
|
|
||||||
|
/**
|
||||||
|
* Connect is a middleware framework for node,
|
||||||
|
* shipping with over 18 bundled middleware and a rich selection of
|
||||||
|
* 3rd-party middleware.
|
||||||
|
*
|
||||||
|
* var app = connect()
|
||||||
|
* .use(connect.logger('dev'))
|
||||||
|
* .use(connect.static('public'))
|
||||||
|
* .use(function(req, res){
|
||||||
|
* res.end('hello world\n');
|
||||||
|
* })
|
||||||
|
* .listen(3000);
|
||||||
|
*
|
||||||
|
* Installation:
|
||||||
|
*
|
||||||
|
* $ npm install connect
|
||||||
|
*
|
||||||
|
* Middleware:
|
||||||
|
*
|
||||||
|
* - [logger](logger.html) request logger with custom format support
|
||||||
|
* - [csrf](csrf.html) Cross-site request forgery protection
|
||||||
|
* - [compress](compress.html) Gzip compression middleware
|
||||||
|
* - [basicAuth](basicAuth.html) basic http authentication
|
||||||
|
* - [bodyParser](bodyParser.html) extensible request body parser
|
||||||
|
* - [json](json.html) application/json parser
|
||||||
|
* - [urlencoded](urlencoded.html) application/x-www-form-urlencoded parser
|
||||||
|
* - [multipart](multipart.html) multipart/form-data parser
|
||||||
|
* - [timeout](timeout.html) request timeouts
|
||||||
|
* - [cookieParser](cookieParser.html) cookie parser
|
||||||
|
* - [session](session.html) session management support with bundled MemoryStore
|
||||||
|
* - [cookieSession](cookieSession.html) cookie-based session support
|
||||||
|
* - [methodOverride](methodOverride.html) faux HTTP method support
|
||||||
|
* - [responseTime](responseTime.html) calculates response-time and exposes via X-Response-Time
|
||||||
|
* - [staticCache](staticCache.html) memory cache layer for the static() middleware
|
||||||
|
* - [static](static.html) streaming static file server supporting `Range` and more
|
||||||
|
* - [directory](directory.html) directory listing middleware
|
||||||
|
* - [vhost](vhost.html) virtual host sub-domain mapping middleware
|
||||||
|
* - [favicon](favicon.html) efficient favicon server (with default icon)
|
||||||
|
* - [limit](limit.html) limit the bytesize of request bodies
|
||||||
|
* - [query](query.html) automatic querystring parser, populating `req.query`
|
||||||
|
* - [errorHandler](errorHandler.html) flexible error handler
|
||||||
|
*
|
||||||
|
* Links:
|
||||||
|
*
|
||||||
|
* - list of [3rd-party](https://github.com/senchalabs/connect/wiki) middleware
|
||||||
|
* - GitHub [repository](http://github.com/senchalabs/connect)
|
||||||
|
* - [test documentation](https://github.com/senchalabs/connect/blob/gh-pages/tests.md)
|
||||||
|
*
|
||||||
|
*/
|
||||||
103
node_modules/connect/lib/middleware/basicAuth.js
generated
vendored
Normal file
@@ -0,0 +1,103 @@
|
|||||||
|
|
||||||
|
/*!
|
||||||
|
* Connect - basicAuth
|
||||||
|
* Copyright(c) 2010 Sencha Inc.
|
||||||
|
* Copyright(c) 2011 TJ Holowaychuk
|
||||||
|
* MIT Licensed
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Module dependencies.
|
||||||
|
*/
|
||||||
|
|
||||||
|
var utils = require('../utils')
|
||||||
|
, unauthorized = utils.unauthorized;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Basic Auth:
|
||||||
|
*
|
||||||
|
* Enfore basic authentication by providing a `callback(user, pass)`,
|
||||||
|
* which must return `true` in order to gain access. Alternatively an async
|
||||||
|
* method is provided as well, invoking `callback(user, pass, callback)`. Populates
|
||||||
|
* `req.user`. The final alternative is simply passing username / password
|
||||||
|
* strings.
|
||||||
|
*
|
||||||
|
* Simple username and password
|
||||||
|
*
|
||||||
|
* connect(connect.basicAuth('username', 'password'));
|
||||||
|
*
|
||||||
|
* Callback verification
|
||||||
|
*
|
||||||
|
* connect()
|
||||||
|
* .use(connect.basicAuth(function(user, pass){
|
||||||
|
* return 'tj' == user & 'wahoo' == pass;
|
||||||
|
* }))
|
||||||
|
*
|
||||||
|
* Async callback verification, accepting `fn(err, user)`.
|
||||||
|
*
|
||||||
|
* connect()
|
||||||
|
* .use(connect.basicAuth(function(user, pass, fn){
|
||||||
|
* User.authenticate({ user: user, pass: pass }, fn);
|
||||||
|
* }))
|
||||||
|
*
|
||||||
|
* @param {Function|String} callback or username
|
||||||
|
* @param {String} realm
|
||||||
|
* @api public
|
||||||
|
*/
|
||||||
|
|
||||||
|
module.exports = function basicAuth(callback, realm) {
|
||||||
|
var username, password;
|
||||||
|
|
||||||
|
// user / pass strings
|
||||||
|
if ('string' == typeof callback) {
|
||||||
|
username = callback;
|
||||||
|
password = realm;
|
||||||
|
if ('string' != typeof password) throw new Error('password argument required');
|
||||||
|
realm = arguments[2];
|
||||||
|
callback = function(user, pass){
|
||||||
|
return user == username && pass == password;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
realm = realm || 'Authorization Required';
|
||||||
|
|
||||||
|
return function(req, res, next) {
|
||||||
|
var authorization = req.headers.authorization;
|
||||||
|
|
||||||
|
if (req.user) return next();
|
||||||
|
if (!authorization) return unauthorized(res, realm);
|
||||||
|
|
||||||
|
var parts = authorization.split(' ');
|
||||||
|
|
||||||
|
if (parts.length !== 2) return next(utils.error(400));
|
||||||
|
|
||||||
|
var scheme = parts[0]
|
||||||
|
, credentials = new Buffer(parts[1], 'base64').toString()
|
||||||
|
, index = credentials.indexOf(':');
|
||||||
|
|
||||||
|
if ('Basic' != scheme || index < 0) return next(utils.error(400));
|
||||||
|
|
||||||
|
var user = credentials.slice(0, index)
|
||||||
|
, pass = credentials.slice(index + 1);
|
||||||
|
|
||||||
|
// async
|
||||||
|
if (callback.length >= 3) {
|
||||||
|
var pause = utils.pause(req);
|
||||||
|
callback(user, pass, function(err, user){
|
||||||
|
if (err || !user) return unauthorized(res, realm);
|
||||||
|
req.user = req.remoteUser = user;
|
||||||
|
next();
|
||||||
|
pause.resume();
|
||||||
|
});
|
||||||
|
// sync
|
||||||
|
} else {
|
||||||
|
if (callback(user, pass)) {
|
||||||
|
req.user = req.remoteUser = user;
|
||||||
|
next();
|
||||||
|
} else {
|
||||||
|
unauthorized(res, realm);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
61
node_modules/connect/lib/middleware/bodyParser.js
generated
vendored
Normal file
@@ -0,0 +1,61 @@
|
|||||||
|
|
||||||
|
/*!
|
||||||
|
* Connect - bodyParser
|
||||||
|
* Copyright(c) 2010 Sencha Inc.
|
||||||
|
* Copyright(c) 2011 TJ Holowaychuk
|
||||||
|
* MIT Licensed
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Module dependencies.
|
||||||
|
*/
|
||||||
|
|
||||||
|
var multipart = require('./multipart')
|
||||||
|
, urlencoded = require('./urlencoded')
|
||||||
|
, json = require('./json');
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Body parser:
|
||||||
|
*
|
||||||
|
* Parse request bodies, supports _application/json_,
|
||||||
|
* _application/x-www-form-urlencoded_, and _multipart/form-data_.
|
||||||
|
*
|
||||||
|
* This is equivalent to:
|
||||||
|
*
|
||||||
|
* app.use(connect.json());
|
||||||
|
* app.use(connect.urlencoded());
|
||||||
|
* app.use(connect.multipart());
|
||||||
|
*
|
||||||
|
* Examples:
|
||||||
|
*
|
||||||
|
* connect()
|
||||||
|
* .use(connect.bodyParser())
|
||||||
|
* .use(function(req, res) {
|
||||||
|
* res.end('viewing user ' + req.body.user.name);
|
||||||
|
* });
|
||||||
|
*
|
||||||
|
* $ curl -d 'user[name]=tj' http://local/
|
||||||
|
* $ curl -d '{"user":{"name":"tj"}}' -H "Content-Type: application/json" http://local/
|
||||||
|
*
|
||||||
|
* View [json](json.html), [urlencoded](urlencoded.html), and [multipart](multipart.html) for more info.
|
||||||
|
*
|
||||||
|
* @param {Object} options
|
||||||
|
* @return {Function}
|
||||||
|
* @api public
|
||||||
|
*/
|
||||||
|
|
||||||
|
exports = module.exports = function bodyParser(options){
|
||||||
|
var _urlencoded = urlencoded(options)
|
||||||
|
, _multipart = multipart(options)
|
||||||
|
, _json = json(options);
|
||||||
|
|
||||||
|
return function bodyParser(req, res, next) {
|
||||||
|
_json(req, res, function(err){
|
||||||
|
if (err) return next(err);
|
||||||
|
_urlencoded(req, res, function(err){
|
||||||
|
if (err) return next(err);
|
||||||
|
_multipart(req, res, next);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
};
|
||||||
152
node_modules/connect/lib/middleware/compress.js
generated
vendored
Normal file
@@ -0,0 +1,152 @@
|
|||||||
|
/*!
|
||||||
|
* Connect - compress
|
||||||
|
* Copyright(c) 2010 Sencha Inc.
|
||||||
|
* Copyright(c) 2011 TJ Holowaychuk
|
||||||
|
* MIT Licensed
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Module dependencies.
|
||||||
|
*/
|
||||||
|
|
||||||
|
var zlib = require('zlib');
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Supported content-encoding methods.
|
||||||
|
*/
|
||||||
|
|
||||||
|
exports.methods = {
|
||||||
|
gzip: zlib.createGzip
|
||||||
|
, deflate: zlib.createDeflate
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Default filter function.
|
||||||
|
*/
|
||||||
|
|
||||||
|
exports.filter = function(req, res){
|
||||||
|
return /json|text|javascript/.test(res.getHeader('Content-Type'));
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Compress:
|
||||||
|
*
|
||||||
|
* Compress response data with gzip/deflate.
|
||||||
|
*
|
||||||
|
* Filter:
|
||||||
|
*
|
||||||
|
* A `filter` callback function may be passed to
|
||||||
|
* replace the default logic of:
|
||||||
|
*
|
||||||
|
* exports.filter = function(req, res){
|
||||||
|
* return /json|text|javascript/.test(res.getHeader('Content-Type'));
|
||||||
|
* };
|
||||||
|
*
|
||||||
|
* Options:
|
||||||
|
*
|
||||||
|
* All remaining options are passed to the gzip/deflate
|
||||||
|
* creation functions. Consult node's docs for additional details.
|
||||||
|
*
|
||||||
|
* - `chunkSize` (default: 16*1024)
|
||||||
|
* - `windowBits`
|
||||||
|
* - `level`: 0-9 where 0 is no compression, and 9 is slow but best compression
|
||||||
|
* - `memLevel`: 1-9 low is slower but uses less memory, high is fast but uses more
|
||||||
|
* - `strategy`: compression strategy
|
||||||
|
*
|
||||||
|
* @param {Object} options
|
||||||
|
* @return {Function}
|
||||||
|
* @api public
|
||||||
|
*/
|
||||||
|
|
||||||
|
module.exports = function compress(options) {
|
||||||
|
options = options || {};
|
||||||
|
var names = Object.keys(exports.methods)
|
||||||
|
, filter = options.filter || exports.filter;
|
||||||
|
|
||||||
|
return function compress(req, res, next){
|
||||||
|
var accept = req.headers['accept-encoding']
|
||||||
|
, vary = res.getHeader('Vary')
|
||||||
|
, write = res.write
|
||||||
|
, end = res.end
|
||||||
|
, stream
|
||||||
|
, method;
|
||||||
|
|
||||||
|
// vary
|
||||||
|
if (!vary) {
|
||||||
|
res.setHeader('Vary', 'Accept-Encoding');
|
||||||
|
} else if (!~vary.indexOf('Accept-Encoding')) {
|
||||||
|
res.setHeader('Vary', vary + ', Accept-Encoding');
|
||||||
|
}
|
||||||
|
|
||||||
|
// proxy
|
||||||
|
|
||||||
|
res.write = function(chunk, encoding){
|
||||||
|
if (!this.headerSent) this._implicitHeader();
|
||||||
|
return stream
|
||||||
|
? stream.write(new Buffer(chunk, encoding))
|
||||||
|
: write.call(res, chunk, encoding);
|
||||||
|
};
|
||||||
|
|
||||||
|
res.end = function(chunk, encoding){
|
||||||
|
if (chunk) this.write(chunk, encoding);
|
||||||
|
return stream
|
||||||
|
? stream.end()
|
||||||
|
: end.call(res);
|
||||||
|
};
|
||||||
|
|
||||||
|
res.on('header', function(){
|
||||||
|
var encoding = res.getHeader('Content-Encoding') || 'identity';
|
||||||
|
|
||||||
|
// already encoded
|
||||||
|
if ('identity' != encoding) return;
|
||||||
|
|
||||||
|
// default request filter
|
||||||
|
if (!filter(req, res)) return;
|
||||||
|
|
||||||
|
// SHOULD use identity
|
||||||
|
if (!accept) return;
|
||||||
|
|
||||||
|
// head
|
||||||
|
if ('HEAD' == req.method) return;
|
||||||
|
|
||||||
|
// default to gzip
|
||||||
|
if ('*' == accept.trim()) method = 'gzip';
|
||||||
|
|
||||||
|
// compression method
|
||||||
|
if (!method) {
|
||||||
|
for (var i = 0, len = names.length; i < len; ++i) {
|
||||||
|
if (~accept.indexOf(names[i])) {
|
||||||
|
method = names[i];
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// compression method
|
||||||
|
if (!method) return;
|
||||||
|
|
||||||
|
// compression stream
|
||||||
|
stream = exports.methods[method](options);
|
||||||
|
|
||||||
|
// header fields
|
||||||
|
res.setHeader('Content-Encoding', method);
|
||||||
|
res.removeHeader('Content-Length');
|
||||||
|
|
||||||
|
// compression
|
||||||
|
|
||||||
|
stream.on('data', function(chunk){
|
||||||
|
write.call(res, chunk);
|
||||||
|
});
|
||||||
|
|
||||||
|
stream.on('end', function(){
|
||||||
|
end.call(res);
|
||||||
|
});
|
||||||
|
|
||||||
|
stream.on('drain', function() {
|
||||||
|
res.emit('drain');
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
next();
|
||||||
|
};
|
||||||
|
};
|
||||||
62
node_modules/connect/lib/middleware/cookieParser.js
generated
vendored
Normal file
@@ -0,0 +1,62 @@
|
|||||||
|
|
||||||
|
/*!
|
||||||
|
* Connect - cookieParser
|
||||||
|
* Copyright(c) 2010 Sencha Inc.
|
||||||
|
* Copyright(c) 2011 TJ Holowaychuk
|
||||||
|
* MIT Licensed
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Module dependencies.
|
||||||
|
*/
|
||||||
|
|
||||||
|
var utils = require('./../utils')
|
||||||
|
, cookie = require('cookie');
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Cookie parser:
|
||||||
|
*
|
||||||
|
* Parse _Cookie_ header and populate `req.cookies`
|
||||||
|
* with an object keyed by the cookie names. Optionally
|
||||||
|
* you may enabled signed cookie support by passing
|
||||||
|
* a `secret` string, which assigns `req.secret` so
|
||||||
|
* it may be used by other middleware.
|
||||||
|
*
|
||||||
|
* Examples:
|
||||||
|
*
|
||||||
|
* connect()
|
||||||
|
* .use(connect.cookieParser('optional secret string'))
|
||||||
|
* .use(function(req, res, next){
|
||||||
|
* res.end(JSON.stringify(req.cookies));
|
||||||
|
* })
|
||||||
|
*
|
||||||
|
* @param {String} secret
|
||||||
|
* @return {Function}
|
||||||
|
* @api public
|
||||||
|
*/
|
||||||
|
|
||||||
|
module.exports = function cookieParser(secret){
|
||||||
|
return function cookieParser(req, res, next) {
|
||||||
|
if (req.cookies) return next();
|
||||||
|
var cookies = req.headers.cookie;
|
||||||
|
|
||||||
|
req.secret = secret;
|
||||||
|
req.cookies = {};
|
||||||
|
req.signedCookies = {};
|
||||||
|
|
||||||
|
if (cookies) {
|
||||||
|
try {
|
||||||
|
req.cookies = cookie.parse(cookies);
|
||||||
|
if (secret) {
|
||||||
|
req.signedCookies = utils.parseSignedCookies(req.cookies, secret);
|
||||||
|
req.signedCookies = utils.parseJSONCookies(req.signedCookies);
|
||||||
|
}
|
||||||
|
req.cookies = utils.parseJSONCookies(req.cookies);
|
||||||
|
} catch (err) {
|
||||||
|
err.status = 400;
|
||||||
|
return next(err);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
next();
|
||||||
|
};
|
||||||
|
};
|
||||||
117
node_modules/connect/lib/middleware/cookieSession.js
generated
vendored
Normal file
@@ -0,0 +1,117 @@
|
|||||||
|
|
||||||
|
/*!
|
||||||
|
* Connect - cookieSession
|
||||||
|
* Copyright(c) 2011 Sencha Inc.
|
||||||
|
* MIT Licensed
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Module dependencies.
|
||||||
|
*/
|
||||||
|
|
||||||
|
var utils = require('./../utils')
|
||||||
|
, Cookie = require('./session/cookie')
|
||||||
|
, debug = require('debug')('connect:cookieSession')
|
||||||
|
, signature = require('cookie-signature')
|
||||||
|
, crc32 = require('buffer-crc32');
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Cookie Session:
|
||||||
|
*
|
||||||
|
* Cookie session middleware.
|
||||||
|
*
|
||||||
|
* var app = connect();
|
||||||
|
* app.use(connect.cookieParser());
|
||||||
|
* app.use(connect.cookieSession({ secret: 'tobo!', cookie: { maxAge: 60 * 60 * 1000 }}));
|
||||||
|
*
|
||||||
|
* Options:
|
||||||
|
*
|
||||||
|
* - `key` cookie name defaulting to `connect.sess`
|
||||||
|
* - `secret` prevents cookie tampering
|
||||||
|
* - `cookie` session cookie settings, defaulting to `{ path: '/', httpOnly: true, maxAge: null }`
|
||||||
|
* - `proxy` trust the reverse proxy when setting secure cookies (via "x-forwarded-proto")
|
||||||
|
*
|
||||||
|
* Clearing sessions:
|
||||||
|
*
|
||||||
|
* To clear the session simply set its value to `null`,
|
||||||
|
* `cookieSession()` will then respond with a 1970 Set-Cookie.
|
||||||
|
*
|
||||||
|
* req.session = null;
|
||||||
|
*
|
||||||
|
* @param {Object} options
|
||||||
|
* @return {Function}
|
||||||
|
* @api public
|
||||||
|
*/
|
||||||
|
|
||||||
|
module.exports = function cookieSession(options){
|
||||||
|
// TODO: utilize Session/Cookie to unify API
|
||||||
|
options = options || {};
|
||||||
|
var key = options.key || 'connect.sess'
|
||||||
|
, trustProxy = options.proxy;
|
||||||
|
|
||||||
|
return function cookieSession(req, res, next) {
|
||||||
|
|
||||||
|
// req.secret is for backwards compatibility
|
||||||
|
var secret = options.secret || req.secret;
|
||||||
|
if (!secret) throw new Error('`secret` option required for cookie sessions');
|
||||||
|
|
||||||
|
// default session
|
||||||
|
req.session = {};
|
||||||
|
var cookie = req.session.cookie = new Cookie(options.cookie);
|
||||||
|
|
||||||
|
// pathname mismatch
|
||||||
|
if (0 != req.originalUrl.indexOf(cookie.path)) return next();
|
||||||
|
|
||||||
|
// cookieParser secret
|
||||||
|
if (!options.secret && req.secret) {
|
||||||
|
req.session = req.signedCookies[key] || {};
|
||||||
|
req.session.cookie = cookie;
|
||||||
|
} else {
|
||||||
|
// TODO: refactor
|
||||||
|
var rawCookie = req.cookies[key];
|
||||||
|
if (rawCookie) {
|
||||||
|
var unsigned = utils.parseSignedCookie(rawCookie, secret);
|
||||||
|
if (unsigned) {
|
||||||
|
var originalHash = crc32.signed(unsigned);
|
||||||
|
req.session = utils.parseJSONCookie(unsigned) || {};
|
||||||
|
req.session.cookie = cookie;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
res.on('header', function(){
|
||||||
|
// removed
|
||||||
|
if (!req.session) {
|
||||||
|
debug('clear session');
|
||||||
|
cookie.expires = new Date(0);
|
||||||
|
res.setHeader('Set-Cookie', cookie.serialize(key, ''));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
delete req.session.cookie;
|
||||||
|
|
||||||
|
// check security
|
||||||
|
var proto = (req.headers['x-forwarded-proto'] || '').toLowerCase()
|
||||||
|
, tls = req.connection.encrypted || (trustProxy && 'https' == proto)
|
||||||
|
, secured = cookie.secure && tls;
|
||||||
|
|
||||||
|
// only send secure cookies via https
|
||||||
|
if (cookie.secure && !secured) return debug('not secured');
|
||||||
|
|
||||||
|
// serialize
|
||||||
|
debug('serializing %j', req.session);
|
||||||
|
var val = 'j:' + JSON.stringify(req.session);
|
||||||
|
|
||||||
|
// compare hashes, no need to set-cookie if unchanged
|
||||||
|
if (originalHash == crc32.signed(val)) return debug('unmodified session');
|
||||||
|
|
||||||
|
// set-cookie
|
||||||
|
val = 's:' + signature.sign(val, secret);
|
||||||
|
val = cookie.serialize(key, val);
|
||||||
|
debug('set-cookie %j', cookie);
|
||||||
|
res.setHeader('Set-Cookie', val);
|
||||||
|
});
|
||||||
|
|
||||||
|
next();
|
||||||
|
};
|
||||||
|
};
|
||||||
73
node_modules/connect/lib/middleware/csrf.js
generated
vendored
Normal file
@@ -0,0 +1,73 @@
|
|||||||
|
/*!
|
||||||
|
* Connect - csrf
|
||||||
|
* Copyright(c) 2011 Sencha Inc.
|
||||||
|
* MIT Licensed
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Module dependencies.
|
||||||
|
*/
|
||||||
|
|
||||||
|
var utils = require('../utils');
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Anti CSRF:
|
||||||
|
*
|
||||||
|
* CRSF protection middleware.
|
||||||
|
*
|
||||||
|
* By default this middleware generates a token named "_csrf"
|
||||||
|
* which should be added to requests which mutate
|
||||||
|
* state, within a hidden form field, query-string etc. This
|
||||||
|
* token is validated against the visitor's `req.session._csrf`
|
||||||
|
* property.
|
||||||
|
*
|
||||||
|
* The default `value` function checks `req.body` generated
|
||||||
|
* by the `bodyParser()` middleware, `req.query` generated
|
||||||
|
* by `query()`, and the "X-CSRF-Token" header field.
|
||||||
|
*
|
||||||
|
* This middleware requires session support, thus should be added
|
||||||
|
* somewhere _below_ `session()` and `cookieParser()`.
|
||||||
|
*
|
||||||
|
* Options:
|
||||||
|
*
|
||||||
|
* - `value` a function accepting the request, returning the token
|
||||||
|
*
|
||||||
|
* @param {Object} options
|
||||||
|
* @api public
|
||||||
|
*/
|
||||||
|
|
||||||
|
module.exports = function csrf(options) {
|
||||||
|
options = options || {};
|
||||||
|
var value = options.value || defaultValue;
|
||||||
|
|
||||||
|
return function(req, res, next){
|
||||||
|
// generate CSRF token
|
||||||
|
var token = req.session._csrf || (req.session._csrf = utils.uid(24));
|
||||||
|
|
||||||
|
// ignore these methods
|
||||||
|
if ('GET' == req.method || 'HEAD' == req.method || 'OPTIONS' == req.method) return next();
|
||||||
|
|
||||||
|
// determine value
|
||||||
|
var val = value(req);
|
||||||
|
|
||||||
|
// check
|
||||||
|
if (val != token) return next(utils.error(403));
|
||||||
|
|
||||||
|
next();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Default value function, checking the `req.body`
|
||||||
|
* and `req.query` for the CSRF token.
|
||||||
|
*
|
||||||
|
* @param {IncomingMessage} req
|
||||||
|
* @return {String}
|
||||||
|
* @api private
|
||||||
|
*/
|
||||||
|
|
||||||
|
function defaultValue(req) {
|
||||||
|
return (req.body && req.body._csrf)
|
||||||
|
|| (req.query && req.query._csrf)
|
||||||
|
|| (req.headers['x-csrf-token']);
|
||||||
|
}
|
||||||
229
node_modules/connect/lib/middleware/directory.js
generated
vendored
Normal file
@@ -0,0 +1,229 @@
|
|||||||
|
|
||||||
|
/*!
|
||||||
|
* Connect - directory
|
||||||
|
* Copyright(c) 2011 Sencha Inc.
|
||||||
|
* Copyright(c) 2011 TJ Holowaychuk
|
||||||
|
* MIT Licensed
|
||||||
|
*/
|
||||||
|
|
||||||
|
// TODO: icon / style for directories
|
||||||
|
// TODO: arrow key navigation
|
||||||
|
// TODO: make icons extensible
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Module dependencies.
|
||||||
|
*/
|
||||||
|
|
||||||
|
var fs = require('fs')
|
||||||
|
, parse = require('url').parse
|
||||||
|
, utils = require('../utils')
|
||||||
|
, path = require('path')
|
||||||
|
, normalize = path.normalize
|
||||||
|
, extname = path.extname
|
||||||
|
, join = path.join;
|
||||||
|
|
||||||
|
/*!
|
||||||
|
* Icon cache.
|
||||||
|
*/
|
||||||
|
|
||||||
|
var cache = {};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Directory:
|
||||||
|
*
|
||||||
|
* Serve directory listings with the given `root` path.
|
||||||
|
*
|
||||||
|
* Options:
|
||||||
|
*
|
||||||
|
* - `hidden` display hidden (dot) files. Defaults to false.
|
||||||
|
* - `icons` display icons. Defaults to false.
|
||||||
|
* - `filter` Apply this filter function to files. Defaults to false.
|
||||||
|
*
|
||||||
|
* @param {String} root
|
||||||
|
* @param {Object} options
|
||||||
|
* @return {Function}
|
||||||
|
* @api public
|
||||||
|
*/
|
||||||
|
|
||||||
|
exports = module.exports = function directory(root, options){
|
||||||
|
options = options || {};
|
||||||
|
|
||||||
|
// root required
|
||||||
|
if (!root) throw new Error('directory() root path required');
|
||||||
|
var hidden = options.hidden
|
||||||
|
, icons = options.icons
|
||||||
|
, filter = options.filter
|
||||||
|
, root = normalize(root);
|
||||||
|
|
||||||
|
return function directory(req, res, next) {
|
||||||
|
if ('GET' != req.method && 'HEAD' != req.method) return next();
|
||||||
|
|
||||||
|
var accept = req.headers.accept || 'text/plain'
|
||||||
|
, url = parse(req.url)
|
||||||
|
, dir = decodeURIComponent(url.pathname)
|
||||||
|
, path = normalize(join(root, dir))
|
||||||
|
, originalUrl = parse(req.originalUrl)
|
||||||
|
, originalDir = decodeURIComponent(originalUrl.pathname)
|
||||||
|
, showUp = path != root && path != root + '/';
|
||||||
|
|
||||||
|
// null byte(s), bad request
|
||||||
|
if (~path.indexOf('\0')) return next(utils.error(400));
|
||||||
|
|
||||||
|
// malicious path, forbidden
|
||||||
|
if (0 != path.indexOf(root)) return next(utils.error(403));
|
||||||
|
|
||||||
|
// check if we have a directory
|
||||||
|
fs.stat(path, function(err, stat){
|
||||||
|
if (err) return 'ENOENT' == err.code
|
||||||
|
? next()
|
||||||
|
: next(err);
|
||||||
|
|
||||||
|
if (!stat.isDirectory()) return next();
|
||||||
|
|
||||||
|
// fetch files
|
||||||
|
fs.readdir(path, function(err, files){
|
||||||
|
if (err) return next(err);
|
||||||
|
if (!hidden) files = removeHidden(files);
|
||||||
|
if (filter) files = files.filter(filter);
|
||||||
|
files.sort();
|
||||||
|
|
||||||
|
// content-negotiation
|
||||||
|
for (var key in exports) {
|
||||||
|
if (~accept.indexOf(key) || ~accept.indexOf('*/*')) {
|
||||||
|
exports[key](req, res, files, next, originalDir, showUp, icons);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// not acceptable
|
||||||
|
next(utils.error(406));
|
||||||
|
});
|
||||||
|
});
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Respond with text/html.
|
||||||
|
*/
|
||||||
|
|
||||||
|
exports.html = function(req, res, files, next, dir, showUp, icons){
|
||||||
|
fs.readFile(__dirname + '/../public/directory.html', 'utf8', function(err, str){
|
||||||
|
if (err) return next(err);
|
||||||
|
fs.readFile(__dirname + '/../public/style.css', 'utf8', function(err, style){
|
||||||
|
if (err) return next(err);
|
||||||
|
if (showUp) files.unshift('..');
|
||||||
|
str = str
|
||||||
|
.replace('{style}', style)
|
||||||
|
.replace('{files}', html(files, dir, icons))
|
||||||
|
.replace('{directory}', dir)
|
||||||
|
.replace('{linked-path}', htmlPath(dir));
|
||||||
|
res.setHeader('Content-Type', 'text/html');
|
||||||
|
res.setHeader('Content-Length', str.length);
|
||||||
|
res.end(str);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Respond with application/json.
|
||||||
|
*/
|
||||||
|
|
||||||
|
exports.json = function(req, res, files){
|
||||||
|
files = JSON.stringify(files);
|
||||||
|
res.setHeader('Content-Type', 'application/json');
|
||||||
|
res.setHeader('Content-Length', files.length);
|
||||||
|
res.end(files);
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Respond with text/plain.
|
||||||
|
*/
|
||||||
|
|
||||||
|
exports.plain = function(req, res, files){
|
||||||
|
files = files.join('\n') + '\n';
|
||||||
|
res.setHeader('Content-Type', 'text/plain');
|
||||||
|
res.setHeader('Content-Length', files.length);
|
||||||
|
res.end(files);
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Map html `dir`, returning a linked path.
|
||||||
|
*/
|
||||||
|
|
||||||
|
function htmlPath(dir) {
|
||||||
|
var curr = [];
|
||||||
|
return dir.split('/').map(function(part){
|
||||||
|
curr.push(part);
|
||||||
|
return '<a href="' + curr.join('/') + '">' + part + '</a>';
|
||||||
|
}).join(' / ');
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Map html `files`, returning an html unordered list.
|
||||||
|
*/
|
||||||
|
|
||||||
|
function html(files, dir, useIcons) {
|
||||||
|
return '<ul id="files">' + files.map(function(file){
|
||||||
|
var icon = ''
|
||||||
|
, classes = [];
|
||||||
|
|
||||||
|
if (useIcons && '..' != file) {
|
||||||
|
icon = icons[extname(file)] || icons.default;
|
||||||
|
icon = '<img src="data:image/png;base64,' + load(icon) + '" />';
|
||||||
|
classes.push('icon');
|
||||||
|
}
|
||||||
|
|
||||||
|
return '<li><a href="'
|
||||||
|
+ join(dir, file)
|
||||||
|
+ '" class="'
|
||||||
|
+ classes.join(' ') + '"'
|
||||||
|
+ ' title="' + file + '">'
|
||||||
|
+ icon + file + '</a></li>';
|
||||||
|
|
||||||
|
}).join('\n') + '</ul>';
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Load and cache the given `icon`.
|
||||||
|
*
|
||||||
|
* @param {String} icon
|
||||||
|
* @return {String}
|
||||||
|
* @api private
|
||||||
|
*/
|
||||||
|
|
||||||
|
function load(icon) {
|
||||||
|
if (cache[icon]) return cache[icon];
|
||||||
|
return cache[icon] = fs.readFileSync(__dirname + '/../public/icons/' + icon, 'base64');
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Filter "hidden" `files`, aka files
|
||||||
|
* beginning with a `.`.
|
||||||
|
*
|
||||||
|
* @param {Array} files
|
||||||
|
* @return {Array}
|
||||||
|
* @api private
|
||||||
|
*/
|
||||||
|
|
||||||
|
function removeHidden(files) {
|
||||||
|
return files.filter(function(file){
|
||||||
|
return '.' != file[0];
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Icon map.
|
||||||
|
*/
|
||||||
|
|
||||||
|
var icons = {
|
||||||
|
'.js': 'page_white_code_red.png'
|
||||||
|
, '.c': 'page_white_c.png'
|
||||||
|
, '.h': 'page_white_h.png'
|
||||||
|
, '.cc': 'page_white_cplusplus.png'
|
||||||
|
, '.php': 'page_white_php.png'
|
||||||
|
, '.rb': 'page_white_ruby.png'
|
||||||
|
, '.cpp': 'page_white_cplusplus.png'
|
||||||
|
, '.swf': 'page_white_flash.png'
|
||||||
|
, '.pdf': 'page_white_acrobat.png'
|
||||||
|
, 'default': 'page_white.png'
|
||||||
|
};
|
||||||
86
node_modules/connect/lib/middleware/errorHandler.js
generated
vendored
Normal file
@@ -0,0 +1,86 @@
|
|||||||
|
/*!
|
||||||
|
* Connect - errorHandler
|
||||||
|
* Copyright(c) 2010 Sencha Inc.
|
||||||
|
* Copyright(c) 2011 TJ Holowaychuk
|
||||||
|
* MIT Licensed
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Module dependencies.
|
||||||
|
*/
|
||||||
|
|
||||||
|
var utils = require('../utils')
|
||||||
|
, fs = require('fs');
|
||||||
|
|
||||||
|
// environment
|
||||||
|
|
||||||
|
var env = process.env.NODE_ENV || 'development';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Error handler:
|
||||||
|
*
|
||||||
|
* Development error handler, providing stack traces
|
||||||
|
* and error message responses for requests accepting text, html,
|
||||||
|
* or json.
|
||||||
|
*
|
||||||
|
* Text:
|
||||||
|
*
|
||||||
|
* By default, and when _text/plain_ is accepted a simple stack trace
|
||||||
|
* or error message will be returned.
|
||||||
|
*
|
||||||
|
* JSON:
|
||||||
|
*
|
||||||
|
* When _application/json_ is accepted, connect will respond with
|
||||||
|
* an object in the form of `{ "error": error }`.
|
||||||
|
*
|
||||||
|
* HTML:
|
||||||
|
*
|
||||||
|
* When accepted connect will output a nice html stack trace.
|
||||||
|
*
|
||||||
|
* @return {Function}
|
||||||
|
* @api public
|
||||||
|
*/
|
||||||
|
|
||||||
|
exports = module.exports = function errorHandler(){
|
||||||
|
return function errorHandler(err, req, res, next){
|
||||||
|
if (err.status) res.statusCode = err.status;
|
||||||
|
if (res.statusCode < 400) res.statusCode = 500;
|
||||||
|
if ('test' != env) console.error(err.stack);
|
||||||
|
var accept = req.headers.accept || '';
|
||||||
|
// html
|
||||||
|
if (~accept.indexOf('html')) {
|
||||||
|
fs.readFile(__dirname + '/../public/style.css', 'utf8', function(e, style){
|
||||||
|
fs.readFile(__dirname + '/../public/error.html', 'utf8', function(e, html){
|
||||||
|
var stack = (err.stack || '')
|
||||||
|
.split('\n').slice(1)
|
||||||
|
.map(function(v){ return '<li>' + v + '</li>'; }).join('');
|
||||||
|
html = html
|
||||||
|
.replace('{style}', style)
|
||||||
|
.replace('{stack}', stack)
|
||||||
|
.replace('{title}', exports.title)
|
||||||
|
.replace('{statusCode}', res.statusCode)
|
||||||
|
.replace(/\{error\}/g, utils.escape(err.toString()));
|
||||||
|
res.setHeader('Content-Type', 'text/html; charset=utf-8');
|
||||||
|
res.end(html);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
// json
|
||||||
|
} else if (~accept.indexOf('json')) {
|
||||||
|
var error = { message: err.message, stack: err.stack };
|
||||||
|
for (var prop in err) error[prop] = err[prop];
|
||||||
|
var json = JSON.stringify({ error: error });
|
||||||
|
res.setHeader('Content-Type', 'application/json');
|
||||||
|
res.end(json);
|
||||||
|
// plain text
|
||||||
|
} else {
|
||||||
|
res.writeHead(res.statusCode, { 'Content-Type': 'text/plain' });
|
||||||
|
res.end(err.stack);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Template title, framework authors may override this value.
|
||||||
|
*/
|
||||||
|
|
||||||
|
exports.title = 'Connect';
|
||||||
80
node_modules/connect/lib/middleware/favicon.js
generated
vendored
Normal file
@@ -0,0 +1,80 @@
|
|||||||
|
/*!
|
||||||
|
* Connect - favicon
|
||||||
|
* Copyright(c) 2010 Sencha Inc.
|
||||||
|
* Copyright(c) 2011 TJ Holowaychuk
|
||||||
|
* MIT Licensed
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Module dependencies.
|
||||||
|
*/
|
||||||
|
|
||||||
|
var fs = require('fs')
|
||||||
|
, utils = require('../utils');
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Favicon:
|
||||||
|
*
|
||||||
|
* By default serves the connect favicon, or the favicon
|
||||||
|
* located by the given `path`.
|
||||||
|
*
|
||||||
|
* Options:
|
||||||
|
*
|
||||||
|
* - `maxAge` cache-control max-age directive, defaulting to 1 day
|
||||||
|
*
|
||||||
|
* Examples:
|
||||||
|
*
|
||||||
|
* Serve default favicon:
|
||||||
|
*
|
||||||
|
* connect()
|
||||||
|
* .use(connect.favicon())
|
||||||
|
*
|
||||||
|
* Serve favicon before logging for brevity:
|
||||||
|
*
|
||||||
|
* connect()
|
||||||
|
* .use(connect.favicon())
|
||||||
|
* .use(connect.logger('dev'))
|
||||||
|
*
|
||||||
|
* Serve custom favicon:
|
||||||
|
*
|
||||||
|
* connect()
|
||||||
|
* .use(connect.favicon('public/favicon.ico'))
|
||||||
|
*
|
||||||
|
* @param {String} path
|
||||||
|
* @param {Object} options
|
||||||
|
* @return {Function}
|
||||||
|
* @api public
|
||||||
|
*/
|
||||||
|
|
||||||
|
module.exports = function favicon(path, options){
|
||||||
|
var options = options || {}
|
||||||
|
, path = path || __dirname + '/../public/favicon.ico'
|
||||||
|
, maxAge = options.maxAge || 86400000
|
||||||
|
, icon; // favicon cache
|
||||||
|
|
||||||
|
return function favicon(req, res, next){
|
||||||
|
if ('/favicon.ico' == req.url) {
|
||||||
|
if (icon) {
|
||||||
|
res.writeHead(200, icon.headers);
|
||||||
|
res.end(icon.body);
|
||||||
|
} else {
|
||||||
|
fs.readFile(path, function(err, buf){
|
||||||
|
if (err) return next(err);
|
||||||
|
icon = {
|
||||||
|
headers: {
|
||||||
|
'Content-Type': 'image/x-icon'
|
||||||
|
, 'Content-Length': buf.length
|
||||||
|
, 'ETag': '"' + utils.md5(buf) + '"'
|
||||||
|
, 'Cache-Control': 'public, max-age=' + (maxAge / 1000)
|
||||||
|
},
|
||||||
|
body: buf
|
||||||
|
};
|
||||||
|
res.writeHead(200, icon.headers);
|
||||||
|
res.end(icon.body);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
next();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
};
|
||||||
86
node_modules/connect/lib/middleware/json.js
generated
vendored
Normal file
@@ -0,0 +1,86 @@
|
|||||||
|
|
||||||
|
/*!
|
||||||
|
* Connect - json
|
||||||
|
* Copyright(c) 2010 Sencha Inc.
|
||||||
|
* Copyright(c) 2011 TJ Holowaychuk
|
||||||
|
* MIT Licensed
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Module dependencies.
|
||||||
|
*/
|
||||||
|
|
||||||
|
var utils = require('../utils')
|
||||||
|
, _limit = require('./limit');
|
||||||
|
|
||||||
|
/**
|
||||||
|
* noop middleware.
|
||||||
|
*/
|
||||||
|
|
||||||
|
function noop(req, res, next) {
|
||||||
|
next();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* JSON:
|
||||||
|
*
|
||||||
|
* Parse JSON request bodies, providing the
|
||||||
|
* parsed object as `req.body`.
|
||||||
|
*
|
||||||
|
* Options:
|
||||||
|
*
|
||||||
|
* - `strict` when `false` anything `JSON.parse()` accepts will be parsed
|
||||||
|
* - `reviver` used as the second "reviver" argument for JSON.parse
|
||||||
|
* - `limit` byte limit disabled by default
|
||||||
|
*
|
||||||
|
* @param {Object} options
|
||||||
|
* @return {Function}
|
||||||
|
* @api public
|
||||||
|
*/
|
||||||
|
|
||||||
|
exports = module.exports = function(options){
|
||||||
|
var options = options || {}
|
||||||
|
, strict = options.strict !== false;
|
||||||
|
|
||||||
|
var limit = options.limit
|
||||||
|
? _limit(options.limit)
|
||||||
|
: noop;
|
||||||
|
|
||||||
|
return function json(req, res, next) {
|
||||||
|
if (req._body) return next();
|
||||||
|
req.body = req.body || {};
|
||||||
|
|
||||||
|
if (!utils.hasBody(req)) return next();
|
||||||
|
|
||||||
|
// check Content-Type
|
||||||
|
if ('application/json' != utils.mime(req)) return next();
|
||||||
|
|
||||||
|
// flag as parsed
|
||||||
|
req._body = true;
|
||||||
|
|
||||||
|
// parse
|
||||||
|
limit(req, res, function(err){
|
||||||
|
if (err) return next(err);
|
||||||
|
var buf = '';
|
||||||
|
req.setEncoding('utf8');
|
||||||
|
req.on('data', function(chunk){ buf += chunk });
|
||||||
|
req.on('end', function(){
|
||||||
|
var first = buf.trim()[0];
|
||||||
|
|
||||||
|
if (0 == buf.length) {
|
||||||
|
return next(utils.error(400, 'invalid json, empty body'));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (strict && '{' != first && '[' != first) return next(utils.error(400, 'invalid json'));
|
||||||
|
try {
|
||||||
|
req.body = JSON.parse(buf, options.reviver);
|
||||||
|
} catch (err){
|
||||||
|
err.body = buf;
|
||||||
|
err.status = 400;
|
||||||
|
return next(err);
|
||||||
|
}
|
||||||
|
next();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
};
|
||||||
|
};
|
||||||
78
node_modules/connect/lib/middleware/limit.js
generated
vendored
Normal file
@@ -0,0 +1,78 @@
|
|||||||
|
|
||||||
|
/*!
|
||||||
|
* Connect - limit
|
||||||
|
* Copyright(c) 2011 TJ Holowaychuk
|
||||||
|
* MIT Licensed
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Module dependencies.
|
||||||
|
*/
|
||||||
|
|
||||||
|
var utils = require('../utils'),
|
||||||
|
brokenPause = utils.brokenPause;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Limit:
|
||||||
|
*
|
||||||
|
* Limit request bodies to the given size in `bytes`.
|
||||||
|
*
|
||||||
|
* A string representation of the bytesize may also be passed,
|
||||||
|
* for example "5mb", "200kb", "1gb", etc.
|
||||||
|
*
|
||||||
|
* connect()
|
||||||
|
* .use(connect.limit('5.5mb'))
|
||||||
|
* .use(handleImageUpload)
|
||||||
|
*
|
||||||
|
* @param {Number|String} bytes
|
||||||
|
* @return {Function}
|
||||||
|
* @api public
|
||||||
|
*/
|
||||||
|
|
||||||
|
module.exports = function limit(bytes){
|
||||||
|
if ('string' == typeof bytes) bytes = utils.parseBytes(bytes);
|
||||||
|
if ('number' != typeof bytes) throw new Error('limit() bytes required');
|
||||||
|
return function limit(req, res, next){
|
||||||
|
var received = 0
|
||||||
|
, len = req.headers['content-length']
|
||||||
|
? parseInt(req.headers['content-length'], 10)
|
||||||
|
: null;
|
||||||
|
|
||||||
|
// self-awareness
|
||||||
|
if (req._limit) return next();
|
||||||
|
req._limit = true;
|
||||||
|
|
||||||
|
// limit by content-length
|
||||||
|
if (len && len > bytes) return next(utils.error(413));
|
||||||
|
|
||||||
|
// limit
|
||||||
|
if (brokenPause) {
|
||||||
|
listen();
|
||||||
|
} else {
|
||||||
|
req.on('newListener', function handler(event) {
|
||||||
|
if (event !== 'data') return;
|
||||||
|
|
||||||
|
req.removeListener('newListener', handler);
|
||||||
|
// Start listening at the end of the current loop
|
||||||
|
// otherwise the request will be consumed too early.
|
||||||
|
// Sideaffect is `limit` will miss the first chunk,
|
||||||
|
// but that's not a big deal.
|
||||||
|
// Unfortunately, the tests don't have large enough
|
||||||
|
// request bodies to test this.
|
||||||
|
process.nextTick(listen);
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
next();
|
||||||
|
|
||||||
|
function listen() {
|
||||||
|
req.on('data', function(chunk) {
|
||||||
|
received += Buffer.isBuffer(chunk)
|
||||||
|
? chunk.length :
|
||||||
|
Buffer.byteLength(chunk);
|
||||||
|
|
||||||
|
if (received > bytes) req.destroy();
|
||||||
|
});
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
339
node_modules/connect/lib/middleware/logger.js
generated
vendored
Normal file
@@ -0,0 +1,339 @@
|
|||||||
|
/*!
|
||||||
|
* Connect - logger
|
||||||
|
* Copyright(c) 2010 Sencha Inc.
|
||||||
|
* Copyright(c) 2011 TJ Holowaychuk
|
||||||
|
* MIT Licensed
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Module dependencies.
|
||||||
|
*/
|
||||||
|
|
||||||
|
var bytes = require('bytes');
|
||||||
|
|
||||||
|
/*!
|
||||||
|
* Log buffer.
|
||||||
|
*/
|
||||||
|
|
||||||
|
var buf = [];
|
||||||
|
|
||||||
|
/*!
|
||||||
|
* Default log buffer duration.
|
||||||
|
*/
|
||||||
|
|
||||||
|
var defaultBufferDuration = 1000;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Logger:
|
||||||
|
*
|
||||||
|
* Log requests with the given `options` or a `format` string.
|
||||||
|
*
|
||||||
|
* Options:
|
||||||
|
*
|
||||||
|
* - `format` Format string, see below for tokens
|
||||||
|
* - `stream` Output stream, defaults to _stdout_
|
||||||
|
* - `buffer` Buffer duration, defaults to 1000ms when _true_
|
||||||
|
* - `immediate` Write log line on request instead of response (for response times)
|
||||||
|
*
|
||||||
|
* Tokens:
|
||||||
|
*
|
||||||
|
* - `:req[header]` ex: `:req[Accept]`
|
||||||
|
* - `:res[header]` ex: `:res[Content-Length]`
|
||||||
|
* - `:http-version`
|
||||||
|
* - `:response-time`
|
||||||
|
* - `:remote-addr`
|
||||||
|
* - `:date`
|
||||||
|
* - `:method`
|
||||||
|
* - `:url`
|
||||||
|
* - `:referrer`
|
||||||
|
* - `:user-agent`
|
||||||
|
* - `:status`
|
||||||
|
*
|
||||||
|
* Formats:
|
||||||
|
*
|
||||||
|
* Pre-defined formats that ship with connect:
|
||||||
|
*
|
||||||
|
* - `default` ':remote-addr - - [:date] ":method :url HTTP/:http-version" :status :res[content-length] ":referrer" ":user-agent"'
|
||||||
|
* - `short` ':remote-addr - :method :url HTTP/:http-version :status :res[content-length] - :response-time ms'
|
||||||
|
* - `tiny` ':method :url :status :res[content-length] - :response-time ms'
|
||||||
|
* - `dev` concise output colored by response status for development use
|
||||||
|
*
|
||||||
|
* Examples:
|
||||||
|
*
|
||||||
|
* connect.logger() // default
|
||||||
|
* connect.logger('short')
|
||||||
|
* connect.logger('tiny')
|
||||||
|
* connect.logger({ immediate: true, format: 'dev' })
|
||||||
|
* connect.logger(':method :url - :referrer')
|
||||||
|
* connect.logger(':req[content-type] -> :res[content-type]')
|
||||||
|
* connect.logger(function(tokens, req, res){ return 'some format string' })
|
||||||
|
*
|
||||||
|
* Defining Tokens:
|
||||||
|
*
|
||||||
|
* To define a token, simply invoke `connect.logger.token()` with the
|
||||||
|
* name and a callback function. The value returned is then available
|
||||||
|
* as ":type" in this case.
|
||||||
|
*
|
||||||
|
* connect.logger.token('type', function(req, res){ return req.headers['content-type']; })
|
||||||
|
*
|
||||||
|
* Defining Formats:
|
||||||
|
*
|
||||||
|
* All default formats are defined this way, however it's public API as well:
|
||||||
|
*
|
||||||
|
* connect.logger.format('name', 'string or function')
|
||||||
|
*
|
||||||
|
* @param {String|Function|Object} format or options
|
||||||
|
* @return {Function}
|
||||||
|
* @api public
|
||||||
|
*/
|
||||||
|
|
||||||
|
exports = module.exports = function logger(options) {
|
||||||
|
if ('object' == typeof options) {
|
||||||
|
options = options || {};
|
||||||
|
} else if (options) {
|
||||||
|
options = { format: options };
|
||||||
|
} else {
|
||||||
|
options = {};
|
||||||
|
}
|
||||||
|
|
||||||
|
// output on request instead of response
|
||||||
|
var immediate = options.immediate;
|
||||||
|
|
||||||
|
// format name
|
||||||
|
var fmt = exports[options.format] || options.format || exports.default;
|
||||||
|
|
||||||
|
// compile format
|
||||||
|
if ('function' != typeof fmt) fmt = compile(fmt);
|
||||||
|
|
||||||
|
// options
|
||||||
|
var stream = options.stream || process.stdout
|
||||||
|
, buffer = options.buffer;
|
||||||
|
|
||||||
|
// buffering support
|
||||||
|
if (buffer) {
|
||||||
|
var realStream = stream
|
||||||
|
, interval = 'number' == typeof buffer
|
||||||
|
? buffer
|
||||||
|
: defaultBufferDuration;
|
||||||
|
|
||||||
|
// flush interval
|
||||||
|
setInterval(function(){
|
||||||
|
if (buf.length) {
|
||||||
|
realStream.write(buf.join(''));
|
||||||
|
buf.length = 0;
|
||||||
|
}
|
||||||
|
}, interval);
|
||||||
|
|
||||||
|
// swap the stream
|
||||||
|
stream = {
|
||||||
|
write: function(str){
|
||||||
|
buf.push(str);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
return function logger(req, res, next) {
|
||||||
|
req._startTime = new Date;
|
||||||
|
|
||||||
|
// immediate
|
||||||
|
if (immediate) {
|
||||||
|
var line = fmt(exports, req, res);
|
||||||
|
if (null == line) return;
|
||||||
|
stream.write(line + '\n');
|
||||||
|
// proxy end to output logging
|
||||||
|
} else {
|
||||||
|
var end = res.end;
|
||||||
|
res.end = function(chunk, encoding){
|
||||||
|
res.end = end;
|
||||||
|
res.end(chunk, encoding);
|
||||||
|
var line = fmt(exports, req, res);
|
||||||
|
if (null == line) return;
|
||||||
|
stream.write(line + '\n');
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
next();
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Compile `fmt` into a function.
|
||||||
|
*
|
||||||
|
* @param {String} fmt
|
||||||
|
* @return {Function}
|
||||||
|
* @api private
|
||||||
|
*/
|
||||||
|
|
||||||
|
function compile(fmt) {
|
||||||
|
fmt = fmt.replace(/"/g, '\\"');
|
||||||
|
var js = ' return "' + fmt.replace(/:([-\w]{2,})(?:\[([^\]]+)\])?/g, function(_, name, arg){
|
||||||
|
return '"\n + (tokens["' + name + '"](req, res, "' + arg + '") || "-") + "';
|
||||||
|
}) + '";'
|
||||||
|
return new Function('tokens, req, res', js);
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Define a token function with the given `name`,
|
||||||
|
* and callback `fn(req, res)`.
|
||||||
|
*
|
||||||
|
* @param {String} name
|
||||||
|
* @param {Function} fn
|
||||||
|
* @return {Object} exports for chaining
|
||||||
|
* @api public
|
||||||
|
*/
|
||||||
|
|
||||||
|
exports.token = function(name, fn) {
|
||||||
|
exports[name] = fn;
|
||||||
|
return this;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Define a `fmt` with the given `name`.
|
||||||
|
*
|
||||||
|
* @param {String} name
|
||||||
|
* @param {String|Function} fmt
|
||||||
|
* @return {Object} exports for chaining
|
||||||
|
* @api public
|
||||||
|
*/
|
||||||
|
|
||||||
|
exports.format = function(name, str){
|
||||||
|
exports[name] = str;
|
||||||
|
return this;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Default format.
|
||||||
|
*/
|
||||||
|
|
||||||
|
exports.format('default', ':remote-addr - - [:date] ":method :url HTTP/:http-version" :status :res[content-length] ":referrer" ":user-agent"');
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Short format.
|
||||||
|
*/
|
||||||
|
|
||||||
|
exports.format('short', ':remote-addr - :method :url HTTP/:http-version :status :res[content-length] - :response-time ms');
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Tiny format.
|
||||||
|
*/
|
||||||
|
|
||||||
|
exports.format('tiny', ':method :url :status :res[content-length] - :response-time ms');
|
||||||
|
|
||||||
|
/**
|
||||||
|
* dev (colored)
|
||||||
|
*/
|
||||||
|
|
||||||
|
exports.format('dev', function(tokens, req, res){
|
||||||
|
var status = res.statusCode
|
||||||
|
, len = parseInt(res.getHeader('Content-Length'), 10)
|
||||||
|
, color = 32;
|
||||||
|
|
||||||
|
if (status >= 500) color = 31
|
||||||
|
else if (status >= 400) color = 33
|
||||||
|
else if (status >= 300) color = 36;
|
||||||
|
|
||||||
|
len = isNaN(len)
|
||||||
|
? ''
|
||||||
|
: len = ' - ' + bytes(len);
|
||||||
|
|
||||||
|
return '\033[90m' + req.method
|
||||||
|
+ ' ' + req.originalUrl + ' '
|
||||||
|
+ '\033[' + color + 'm' + res.statusCode
|
||||||
|
+ ' \033[90m'
|
||||||
|
+ (new Date - req._startTime)
|
||||||
|
+ 'ms' + len
|
||||||
|
+ '\033[0m';
|
||||||
|
});
|
||||||
|
|
||||||
|
/**
|
||||||
|
* request url
|
||||||
|
*/
|
||||||
|
|
||||||
|
exports.token('url', function(req){
|
||||||
|
return req.originalUrl || req.url;
|
||||||
|
});
|
||||||
|
|
||||||
|
/**
|
||||||
|
* request method
|
||||||
|
*/
|
||||||
|
|
||||||
|
exports.token('method', function(req){
|
||||||
|
return req.method;
|
||||||
|
});
|
||||||
|
|
||||||
|
/**
|
||||||
|
* response time in milliseconds
|
||||||
|
*/
|
||||||
|
|
||||||
|
exports.token('response-time', function(req){
|
||||||
|
return new Date - req._startTime;
|
||||||
|
});
|
||||||
|
|
||||||
|
/**
|
||||||
|
* UTC date
|
||||||
|
*/
|
||||||
|
|
||||||
|
exports.token('date', function(){
|
||||||
|
return new Date().toUTCString();
|
||||||
|
});
|
||||||
|
|
||||||
|
/**
|
||||||
|
* response status code
|
||||||
|
*/
|
||||||
|
|
||||||
|
exports.token('status', function(req, res){
|
||||||
|
return res.statusCode;
|
||||||
|
});
|
||||||
|
|
||||||
|
/**
|
||||||
|
* normalized referrer
|
||||||
|
*/
|
||||||
|
|
||||||
|
exports.token('referrer', function(req){
|
||||||
|
return req.headers['referer'] || req.headers['referrer'];
|
||||||
|
});
|
||||||
|
|
||||||
|
/**
|
||||||
|
* remote address
|
||||||
|
*/
|
||||||
|
|
||||||
|
exports.token('remote-addr', function(req){
|
||||||
|
if (req.ip) return req.ip;
|
||||||
|
var sock = req.socket;
|
||||||
|
if (sock.socket) return sock.socket.remoteAddress;
|
||||||
|
return sock.remoteAddress;
|
||||||
|
});
|
||||||
|
|
||||||
|
/**
|
||||||
|
* HTTP version
|
||||||
|
*/
|
||||||
|
|
||||||
|
exports.token('http-version', function(req){
|
||||||
|
return req.httpVersionMajor + '.' + req.httpVersionMinor;
|
||||||
|
});
|
||||||
|
|
||||||
|
/**
|
||||||
|
* UA string
|
||||||
|
*/
|
||||||
|
|
||||||
|
exports.token('user-agent', function(req){
|
||||||
|
return req.headers['user-agent'];
|
||||||
|
});
|
||||||
|
|
||||||
|
/**
|
||||||
|
* request header
|
||||||
|
*/
|
||||||
|
|
||||||
|
exports.token('req', function(req, res, field){
|
||||||
|
return req.headers[field.toLowerCase()];
|
||||||
|
});
|
||||||
|
|
||||||
|
/**
|
||||||
|
* response header
|
||||||
|
*/
|
||||||
|
|
||||||
|
exports.token('res', function(req, res, field){
|
||||||
|
return (res._headers || {})[field.toLowerCase()];
|
||||||
|
});
|
||||||
|
|
||||||
40
node_modules/connect/lib/middleware/methodOverride.js
generated
vendored
Normal file
@@ -0,0 +1,40 @@
|
|||||||
|
|
||||||
|
/*!
|
||||||
|
* Connect - methodOverride
|
||||||
|
* Copyright(c) 2010 Sencha Inc.
|
||||||
|
* Copyright(c) 2011 TJ Holowaychuk
|
||||||
|
* MIT Licensed
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Method Override:
|
||||||
|
*
|
||||||
|
* Provides faux HTTP method support.
|
||||||
|
*
|
||||||
|
* Pass an optional `key` to use when checking for
|
||||||
|
* a method override, othewise defaults to _\_method_.
|
||||||
|
* The original method is available via `req.originalMethod`.
|
||||||
|
*
|
||||||
|
* @param {String} key
|
||||||
|
* @return {Function}
|
||||||
|
* @api public
|
||||||
|
*/
|
||||||
|
|
||||||
|
module.exports = function methodOverride(key){
|
||||||
|
key = key || "_method";
|
||||||
|
return function methodOverride(req, res, next) {
|
||||||
|
req.originalMethod = req.originalMethod || req.method;
|
||||||
|
|
||||||
|
// req.body
|
||||||
|
if (req.body && key in req.body) {
|
||||||
|
req.method = req.body[key].toUpperCase();
|
||||||
|
delete req.body[key];
|
||||||
|
// check X-HTTP-Method-Override
|
||||||
|
} else if (req.headers['x-http-method-override']) {
|
||||||
|
req.method = req.headers['x-http-method-override'].toUpperCase();
|
||||||
|
}
|
||||||
|
|
||||||
|
next();
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
133
node_modules/connect/lib/middleware/multipart.js
generated
vendored
Normal file
@@ -0,0 +1,133 @@
|
|||||||
|
/*!
|
||||||
|
* Connect - multipart
|
||||||
|
* Copyright(c) 2010 Sencha Inc.
|
||||||
|
* Copyright(c) 2011 TJ Holowaychuk
|
||||||
|
* MIT Licensed
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Module dependencies.
|
||||||
|
*/
|
||||||
|
|
||||||
|
var formidable = require('formidable')
|
||||||
|
, _limit = require('./limit')
|
||||||
|
, utils = require('../utils')
|
||||||
|
, qs = require('qs');
|
||||||
|
|
||||||
|
/**
|
||||||
|
* noop middleware.
|
||||||
|
*/
|
||||||
|
|
||||||
|
function noop(req, res, next) {
|
||||||
|
next();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Multipart:
|
||||||
|
*
|
||||||
|
* Parse multipart/form-data request bodies,
|
||||||
|
* providing the parsed object as `req.body`
|
||||||
|
* and `req.files`.
|
||||||
|
*
|
||||||
|
* Configuration:
|
||||||
|
*
|
||||||
|
* The options passed are merged with [formidable](https://github.com/felixge/node-formidable)'s
|
||||||
|
* `IncomingForm` object, allowing you to configure the upload directory,
|
||||||
|
* size limits, etc. For example if you wish to change the upload dir do the following.
|
||||||
|
*
|
||||||
|
* app.use(connect.multipart({ uploadDir: path }));
|
||||||
|
*
|
||||||
|
* Options:
|
||||||
|
*
|
||||||
|
* - `limit` byte limit defaulting to none
|
||||||
|
* - `defer` defers processing and exposes the Formidable form object as `req.form`.
|
||||||
|
* `next()` is called without waiting for the form's "end" event.
|
||||||
|
* This option is useful if you need to bind to the "progress" event, for example.
|
||||||
|
*
|
||||||
|
* @param {Object} options
|
||||||
|
* @return {Function}
|
||||||
|
* @api public
|
||||||
|
*/
|
||||||
|
|
||||||
|
exports = module.exports = function(options){
|
||||||
|
options = options || {};
|
||||||
|
|
||||||
|
var limit = options.limit
|
||||||
|
? _limit(options.limit)
|
||||||
|
: noop;
|
||||||
|
|
||||||
|
return function multipart(req, res, next) {
|
||||||
|
if (req._body) return next();
|
||||||
|
req.body = req.body || {};
|
||||||
|
req.files = req.files || {};
|
||||||
|
|
||||||
|
if (!utils.hasBody(req)) return next();
|
||||||
|
|
||||||
|
// ignore GET
|
||||||
|
if ('GET' == req.method || 'HEAD' == req.method) return next();
|
||||||
|
|
||||||
|
// check Content-Type
|
||||||
|
if ('multipart/form-data' != utils.mime(req)) return next();
|
||||||
|
|
||||||
|
// flag as parsed
|
||||||
|
req._body = true;
|
||||||
|
|
||||||
|
// parse
|
||||||
|
limit(req, res, function(err){
|
||||||
|
if (err) return next(err);
|
||||||
|
|
||||||
|
var form = new formidable.IncomingForm
|
||||||
|
, data = {}
|
||||||
|
, files = {}
|
||||||
|
, done;
|
||||||
|
|
||||||
|
Object.keys(options).forEach(function(key){
|
||||||
|
form[key] = options[key];
|
||||||
|
});
|
||||||
|
|
||||||
|
function ondata(name, val, data){
|
||||||
|
if (Array.isArray(data[name])) {
|
||||||
|
data[name].push(val);
|
||||||
|
} else if (data[name]) {
|
||||||
|
data[name] = [data[name], val];
|
||||||
|
} else {
|
||||||
|
data[name] = val;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
form.on('field', function(name, val){
|
||||||
|
ondata(name, val, data);
|
||||||
|
});
|
||||||
|
|
||||||
|
form.on('file', function(name, val){
|
||||||
|
ondata(name, val, files);
|
||||||
|
});
|
||||||
|
|
||||||
|
form.on('error', function(err){
|
||||||
|
if (!options.defer) {
|
||||||
|
err.status = 400;
|
||||||
|
next(err);
|
||||||
|
}
|
||||||
|
done = true;
|
||||||
|
});
|
||||||
|
|
||||||
|
form.on('end', function(){
|
||||||
|
if (done) return;
|
||||||
|
try {
|
||||||
|
req.body = qs.parse(data);
|
||||||
|
req.files = qs.parse(files);
|
||||||
|
if (!options.defer) next();
|
||||||
|
} catch (err) {
|
||||||
|
form.emit('error', err);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
form.parse(req);
|
||||||
|
|
||||||
|
if (options.defer) {
|
||||||
|
req.form = form;
|
||||||
|
next();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
};
|
||||||
46
node_modules/connect/lib/middleware/query.js
generated
vendored
Normal file
@@ -0,0 +1,46 @@
|
|||||||
|
/*!
|
||||||
|
* Connect - query
|
||||||
|
* Copyright(c) 2011 TJ Holowaychuk
|
||||||
|
* Copyright(c) 2011 Sencha Inc.
|
||||||
|
* MIT Licensed
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Module dependencies.
|
||||||
|
*/
|
||||||
|
|
||||||
|
var qs = require('qs')
|
||||||
|
, parse = require('../utils').parseUrl;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Query:
|
||||||
|
*
|
||||||
|
* Automatically parse the query-string when available,
|
||||||
|
* populating the `req.query` object.
|
||||||
|
*
|
||||||
|
* Examples:
|
||||||
|
*
|
||||||
|
* connect()
|
||||||
|
* .use(connect.query())
|
||||||
|
* .use(function(req, res){
|
||||||
|
* res.end(JSON.stringify(req.query));
|
||||||
|
* });
|
||||||
|
*
|
||||||
|
* The `options` passed are provided to qs.parse function.
|
||||||
|
*
|
||||||
|
* @param {Object} options
|
||||||
|
* @return {Function}
|
||||||
|
* @api public
|
||||||
|
*/
|
||||||
|
|
||||||
|
module.exports = function query(options){
|
||||||
|
return function query(req, res, next){
|
||||||
|
if (!req.query) {
|
||||||
|
req.query = ~req.url.indexOf('?')
|
||||||
|
? qs.parse(parse(req).query, options)
|
||||||
|
: {};
|
||||||
|
}
|
||||||
|
|
||||||
|
next();
|
||||||
|
};
|
||||||
|
};
|
||||||
32
node_modules/connect/lib/middleware/responseTime.js
generated
vendored
Normal file
@@ -0,0 +1,32 @@
|
|||||||
|
|
||||||
|
/*!
|
||||||
|
* Connect - responseTime
|
||||||
|
* Copyright(c) 2011 TJ Holowaychuk
|
||||||
|
* MIT Licensed
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Reponse time:
|
||||||
|
*
|
||||||
|
* Adds the `X-Response-Time` header displaying the response
|
||||||
|
* duration in milliseconds.
|
||||||
|
*
|
||||||
|
* @return {Function}
|
||||||
|
* @api public
|
||||||
|
*/
|
||||||
|
|
||||||
|
module.exports = function responseTime(){
|
||||||
|
return function(req, res, next){
|
||||||
|
var start = new Date;
|
||||||
|
|
||||||
|
if (res._responseTime) return next();
|
||||||
|
res._responseTime = true;
|
||||||
|
|
||||||
|
res.on('header', function(){
|
||||||
|
var duration = new Date - start;
|
||||||
|
res.setHeader('X-Response-Time', duration + 'ms');
|
||||||
|
});
|
||||||
|
|
||||||
|
next();
|
||||||
|
};
|
||||||
|
};
|
||||||
356
node_modules/connect/lib/middleware/session.js
generated
vendored
Normal file
@@ -0,0 +1,356 @@
|
|||||||
|
|
||||||
|
/*!
|
||||||
|
* Connect - session
|
||||||
|
* Copyright(c) 2010 Sencha Inc.
|
||||||
|
* Copyright(c) 2011 TJ Holowaychuk
|
||||||
|
* MIT Licensed
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Module dependencies.
|
||||||
|
*/
|
||||||
|
|
||||||
|
var Session = require('./session/session')
|
||||||
|
, debug = require('debug')('connect:session')
|
||||||
|
, MemoryStore = require('./session/memory')
|
||||||
|
, signature = require('cookie-signature')
|
||||||
|
, Cookie = require('./session/cookie')
|
||||||
|
, Store = require('./session/store')
|
||||||
|
, utils = require('./../utils')
|
||||||
|
, parse = utils.parseUrl
|
||||||
|
, crc32 = require('buffer-crc32');
|
||||||
|
|
||||||
|
// environment
|
||||||
|
|
||||||
|
var env = process.env.NODE_ENV;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Expose the middleware.
|
||||||
|
*/
|
||||||
|
|
||||||
|
exports = module.exports = session;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Expose constructors.
|
||||||
|
*/
|
||||||
|
|
||||||
|
exports.Store = Store;
|
||||||
|
exports.Cookie = Cookie;
|
||||||
|
exports.Session = Session;
|
||||||
|
exports.MemoryStore = MemoryStore;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Warning message for `MemoryStore` usage in production.
|
||||||
|
*/
|
||||||
|
|
||||||
|
var warning = 'Warning: connection.session() MemoryStore is not\n'
|
||||||
|
+ 'designed for a production environment, as it will leak\n'
|
||||||
|
+ 'memory, and will not scale past a single process.';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Session:
|
||||||
|
*
|
||||||
|
* Setup session store with the given `options`.
|
||||||
|
*
|
||||||
|
* Session data is _not_ saved in the cookie itself, however
|
||||||
|
* cookies are used, so we must use the [cookieParser()](cookieParser.html)
|
||||||
|
* middleware _before_ `session()`.
|
||||||
|
*
|
||||||
|
* Examples:
|
||||||
|
*
|
||||||
|
* connect()
|
||||||
|
* .use(connect.cookieParser())
|
||||||
|
* .use(connect.session({ secret: 'keyboard cat', key: 'sid', cookie: { secure: true }}))
|
||||||
|
*
|
||||||
|
* Options:
|
||||||
|
*
|
||||||
|
* - `key` cookie name defaulting to `connect.sid`
|
||||||
|
* - `store` session store instance
|
||||||
|
* - `secret` session cookie is signed with this secret to prevent tampering
|
||||||
|
* - `cookie` session cookie settings, defaulting to `{ path: '/', httpOnly: true, maxAge: null }`
|
||||||
|
* - `proxy` trust the reverse proxy when setting secure cookies (via "x-forwarded-proto")
|
||||||
|
*
|
||||||
|
* Cookie option:
|
||||||
|
*
|
||||||
|
* By default `cookie.maxAge` is `null`, meaning no "expires" parameter is set
|
||||||
|
* so the cookie becomes a browser-session cookie. When the user closes the
|
||||||
|
* browser the cookie (and session) will be removed.
|
||||||
|
*
|
||||||
|
* ## req.session
|
||||||
|
*
|
||||||
|
* To store or access session data, simply use the request property `req.session`,
|
||||||
|
* which is (generally) serialized as JSON by the store, so nested objects
|
||||||
|
* are typically fine. For example below is a user-specific view counter:
|
||||||
|
*
|
||||||
|
* connect()
|
||||||
|
* .use(connect.favicon())
|
||||||
|
* .use(connect.cookieParser())
|
||||||
|
* .use(connect.session({ secret: 'keyboard cat', cookie: { maxAge: 60000 }}))
|
||||||
|
* .use(function(req, res, next){
|
||||||
|
* var sess = req.session;
|
||||||
|
* if (sess.views) {
|
||||||
|
* res.setHeader('Content-Type', 'text/html');
|
||||||
|
* res.write('<p>views: ' + sess.views + '</p>');
|
||||||
|
* res.write('<p>expires in: ' + (sess.cookie.maxAge / 1000) + 's</p>');
|
||||||
|
* res.end();
|
||||||
|
* sess.views++;
|
||||||
|
* } else {
|
||||||
|
* sess.views = 1;
|
||||||
|
* res.end('welcome to the session demo. refresh!');
|
||||||
|
* }
|
||||||
|
* }
|
||||||
|
* )).listen(3000);
|
||||||
|
*
|
||||||
|
* ## Session#regenerate()
|
||||||
|
*
|
||||||
|
* To regenerate the session simply invoke the method, once complete
|
||||||
|
* a new SID and `Session` instance will be initialized at `req.session`.
|
||||||
|
*
|
||||||
|
* req.session.regenerate(function(err){
|
||||||
|
* // will have a new session here
|
||||||
|
* });
|
||||||
|
*
|
||||||
|
* ## Session#destroy()
|
||||||
|
*
|
||||||
|
* Destroys the session, removing `req.session`, will be re-generated next request.
|
||||||
|
*
|
||||||
|
* req.session.destroy(function(err){
|
||||||
|
* // cannot access session here
|
||||||
|
* });
|
||||||
|
*
|
||||||
|
* ## Session#reload()
|
||||||
|
*
|
||||||
|
* Reloads the session data.
|
||||||
|
*
|
||||||
|
* req.session.reload(function(err){
|
||||||
|
* // session updated
|
||||||
|
* });
|
||||||
|
*
|
||||||
|
* ## Session#save()
|
||||||
|
*
|
||||||
|
* Save the session.
|
||||||
|
*
|
||||||
|
* req.session.save(function(err){
|
||||||
|
* // session saved
|
||||||
|
* });
|
||||||
|
*
|
||||||
|
* ## Session#touch()
|
||||||
|
*
|
||||||
|
* Updates the `.maxAge` property. Typically this is
|
||||||
|
* not necessary to call, as the session middleware does this for you.
|
||||||
|
*
|
||||||
|
* ## Session#cookie
|
||||||
|
*
|
||||||
|
* Each session has a unique cookie object accompany it. This allows
|
||||||
|
* you to alter the session cookie per visitor. For example we can
|
||||||
|
* set `req.session.cookie.expires` to `false` to enable the cookie
|
||||||
|
* to remain for only the duration of the user-agent.
|
||||||
|
*
|
||||||
|
* ## Session#maxAge
|
||||||
|
*
|
||||||
|
* Alternatively `req.session.cookie.maxAge` will return the time
|
||||||
|
* remaining in milliseconds, which we may also re-assign a new value
|
||||||
|
* to adjust the `.expires` property appropriately. The following
|
||||||
|
* are essentially equivalent
|
||||||
|
*
|
||||||
|
* var hour = 3600000;
|
||||||
|
* req.session.cookie.expires = new Date(Date.now() + hour);
|
||||||
|
* req.session.cookie.maxAge = hour;
|
||||||
|
*
|
||||||
|
* For example when `maxAge` is set to `60000` (one minute), and 30 seconds
|
||||||
|
* has elapsed it will return `30000` until the current request has completed,
|
||||||
|
* at which time `req.session.touch()` is called to reset `req.session.maxAge`
|
||||||
|
* to its original value.
|
||||||
|
*
|
||||||
|
* req.session.cookie.maxAge;
|
||||||
|
* // => 30000
|
||||||
|
*
|
||||||
|
* Session Store Implementation:
|
||||||
|
*
|
||||||
|
* Every session store _must_ implement the following methods
|
||||||
|
*
|
||||||
|
* - `.get(sid, callback)`
|
||||||
|
* - `.set(sid, session, callback)`
|
||||||
|
* - `.destroy(sid, callback)`
|
||||||
|
*
|
||||||
|
* Recommended methods include, but are not limited to:
|
||||||
|
*
|
||||||
|
* - `.length(callback)`
|
||||||
|
* - `.clear(callback)`
|
||||||
|
*
|
||||||
|
* For an example implementation view the [connect-redis](http://github.com/visionmedia/connect-redis) repo.
|
||||||
|
*
|
||||||
|
* @param {Object} options
|
||||||
|
* @return {Function}
|
||||||
|
* @api public
|
||||||
|
*/
|
||||||
|
|
||||||
|
function session(options){
|
||||||
|
var options = options || {}
|
||||||
|
, key = options.key || 'connect.sid'
|
||||||
|
, store = options.store || new MemoryStore
|
||||||
|
, cookie = options.cookie || {}
|
||||||
|
, trustProxy = options.proxy
|
||||||
|
, storeReady = true;
|
||||||
|
|
||||||
|
// notify user that this store is not
|
||||||
|
// meant for a production environment
|
||||||
|
if ('production' == env && store instanceof MemoryStore) {
|
||||||
|
console.warn(warning);
|
||||||
|
}
|
||||||
|
|
||||||
|
// generates the new session
|
||||||
|
store.generate = function(req){
|
||||||
|
req.sessionID = utils.uid(24);
|
||||||
|
req.session = new Session(req);
|
||||||
|
req.session.cookie = new Cookie(cookie);
|
||||||
|
};
|
||||||
|
|
||||||
|
store.on('disconnect', function(){ storeReady = false; });
|
||||||
|
store.on('connect', function(){ storeReady = true; });
|
||||||
|
|
||||||
|
return function session(req, res, next) {
|
||||||
|
// self-awareness
|
||||||
|
if (req.session) return next();
|
||||||
|
|
||||||
|
// Handle connection as if there is no session if
|
||||||
|
// the store has temporarily disconnected etc
|
||||||
|
if (!storeReady) return debug('store is disconnected'), next();
|
||||||
|
|
||||||
|
// pathname mismatch
|
||||||
|
if (0 != req.originalUrl.indexOf(cookie.path || '/')) return next();
|
||||||
|
|
||||||
|
// backwards compatibility for signed cookies
|
||||||
|
// req.secret is passed from the cookie parser middleware
|
||||||
|
var secret = options.secret || req.secret;
|
||||||
|
|
||||||
|
// ensure secret is available or bail
|
||||||
|
if (!secret) throw new Error('`secret` option required for sessions');
|
||||||
|
|
||||||
|
// parse url
|
||||||
|
var originalHash
|
||||||
|
, originalId;
|
||||||
|
|
||||||
|
// expose store
|
||||||
|
req.sessionStore = store;
|
||||||
|
|
||||||
|
// grab the session cookie value and check the signature
|
||||||
|
var rawCookie = req.cookies[key];
|
||||||
|
|
||||||
|
// get signedCookies for backwards compat with signed cookies
|
||||||
|
var unsignedCookie = req.signedCookies[key];
|
||||||
|
|
||||||
|
if (!unsignedCookie && rawCookie) {
|
||||||
|
unsignedCookie = utils.parseSignedCookie(rawCookie, secret);
|
||||||
|
}
|
||||||
|
|
||||||
|
// set-cookie
|
||||||
|
res.on('header', function(){
|
||||||
|
if (!req.session) return;
|
||||||
|
var cookie = req.session.cookie
|
||||||
|
, proto = (req.headers['x-forwarded-proto'] || '').split(',')[0].toLowerCase().trim()
|
||||||
|
, tls = req.connection.encrypted || (trustProxy && 'https' == proto)
|
||||||
|
, secured = cookie.secure && tls
|
||||||
|
, isNew = unsignedCookie != req.sessionID;
|
||||||
|
|
||||||
|
// only send secure cookies via https
|
||||||
|
if (cookie.secure && !secured) return debug('not secured');
|
||||||
|
|
||||||
|
// long expires, handle expiry server-side
|
||||||
|
if (!isNew && cookie.hasLongExpires) return debug('already set cookie');
|
||||||
|
|
||||||
|
// browser-session length cookie
|
||||||
|
if (null == cookie.expires) {
|
||||||
|
if (!isNew) return debug('already set browser-session cookie');
|
||||||
|
// compare hashes and ids
|
||||||
|
} else if (originalHash == hash(req.session) && originalId == req.session.id) {
|
||||||
|
return debug('unmodified session');
|
||||||
|
}
|
||||||
|
|
||||||
|
var val = 's:' + signature.sign(req.sessionID, secret);
|
||||||
|
val = cookie.serialize(key, val);
|
||||||
|
debug('set-cookie %s', val);
|
||||||
|
res.setHeader('Set-Cookie', val);
|
||||||
|
});
|
||||||
|
|
||||||
|
// proxy end() to commit the session
|
||||||
|
var end = res.end;
|
||||||
|
res.end = function(data, encoding){
|
||||||
|
res.end = end;
|
||||||
|
if (!req.session) return res.end(data, encoding);
|
||||||
|
debug('saving');
|
||||||
|
req.session.resetMaxAge();
|
||||||
|
req.session.save(function(err){
|
||||||
|
if (err) console.error(err.stack);
|
||||||
|
debug('saved');
|
||||||
|
res.end(data, encoding);
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
// generate the session
|
||||||
|
function generate() {
|
||||||
|
store.generate(req);
|
||||||
|
}
|
||||||
|
|
||||||
|
// get the sessionID from the cookie
|
||||||
|
req.sessionID = unsignedCookie;
|
||||||
|
|
||||||
|
// generate a session if the browser doesn't send a sessionID
|
||||||
|
if (!req.sessionID) {
|
||||||
|
debug('no SID sent, generating session');
|
||||||
|
generate();
|
||||||
|
next();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// generate the session object
|
||||||
|
var pause = utils.pause(req);
|
||||||
|
debug('fetching %s', req.sessionID);
|
||||||
|
store.get(req.sessionID, function(err, sess){
|
||||||
|
// proxy to resume() events
|
||||||
|
var _next = next;
|
||||||
|
next = function(err){
|
||||||
|
_next(err);
|
||||||
|
pause.resume();
|
||||||
|
};
|
||||||
|
|
||||||
|
// error handling
|
||||||
|
if (err) {
|
||||||
|
debug('error %j', err);
|
||||||
|
if ('ENOENT' == err.code) {
|
||||||
|
generate();
|
||||||
|
next();
|
||||||
|
} else {
|
||||||
|
next(err);
|
||||||
|
}
|
||||||
|
// no session
|
||||||
|
} else if (!sess) {
|
||||||
|
debug('no session found');
|
||||||
|
generate();
|
||||||
|
next();
|
||||||
|
// populate req.session
|
||||||
|
} else {
|
||||||
|
debug('session found');
|
||||||
|
store.createSession(req, sess);
|
||||||
|
originalId = req.sessionID;
|
||||||
|
originalHash = hash(sess);
|
||||||
|
next();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Hash the given `sess` object omitting changes
|
||||||
|
* to `.cookie`.
|
||||||
|
*
|
||||||
|
* @param {Object} sess
|
||||||
|
* @return {String}
|
||||||
|
* @api private
|
||||||
|
*/
|
||||||
|
|
||||||
|
function hash(sess) {
|
||||||
|
return crc32.signed(JSON.stringify(sess, function(key, val){
|
||||||
|
if ('cookie' != key) return val;
|
||||||
|
}));
|
||||||
|
}
|
||||||
140
node_modules/connect/lib/middleware/session/cookie.js
generated
vendored
Normal file
@@ -0,0 +1,140 @@
|
|||||||
|
|
||||||
|
/*!
|
||||||
|
* Connect - session - Cookie
|
||||||
|
* Copyright(c) 2010 Sencha Inc.
|
||||||
|
* Copyright(c) 2011 TJ Holowaychuk
|
||||||
|
* MIT Licensed
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Module dependencies.
|
||||||
|
*/
|
||||||
|
|
||||||
|
var utils = require('../../utils')
|
||||||
|
, cookie = require('cookie');
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Initialize a new `Cookie` with the given `options`.
|
||||||
|
*
|
||||||
|
* @param {IncomingMessage} req
|
||||||
|
* @param {Object} options
|
||||||
|
* @api private
|
||||||
|
*/
|
||||||
|
|
||||||
|
var Cookie = module.exports = function Cookie(options) {
|
||||||
|
this.path = '/';
|
||||||
|
this.maxAge = null;
|
||||||
|
this.httpOnly = true;
|
||||||
|
if (options) utils.merge(this, options);
|
||||||
|
this.originalMaxAge = undefined == this.originalMaxAge
|
||||||
|
? this.maxAge
|
||||||
|
: this.originalMaxAge;
|
||||||
|
};
|
||||||
|
|
||||||
|
/*!
|
||||||
|
* Prototype.
|
||||||
|
*/
|
||||||
|
|
||||||
|
Cookie.prototype = {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set expires `date`.
|
||||||
|
*
|
||||||
|
* @param {Date} date
|
||||||
|
* @api public
|
||||||
|
*/
|
||||||
|
|
||||||
|
set expires(date) {
|
||||||
|
this._expires = date;
|
||||||
|
this.originalMaxAge = this.maxAge;
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get expires `date`.
|
||||||
|
*
|
||||||
|
* @return {Date}
|
||||||
|
* @api public
|
||||||
|
*/
|
||||||
|
|
||||||
|
get expires() {
|
||||||
|
return this._expires;
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set expires via max-age in `ms`.
|
||||||
|
*
|
||||||
|
* @param {Number} ms
|
||||||
|
* @api public
|
||||||
|
*/
|
||||||
|
|
||||||
|
set maxAge(ms) {
|
||||||
|
this.expires = 'number' == typeof ms
|
||||||
|
? new Date(Date.now() + ms)
|
||||||
|
: ms;
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get expires max-age in `ms`.
|
||||||
|
*
|
||||||
|
* @return {Number}
|
||||||
|
* @api public
|
||||||
|
*/
|
||||||
|
|
||||||
|
get maxAge() {
|
||||||
|
return this.expires instanceof Date
|
||||||
|
? this.expires.valueOf() - Date.now()
|
||||||
|
: this.expires;
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return cookie data object.
|
||||||
|
*
|
||||||
|
* @return {Object}
|
||||||
|
* @api private
|
||||||
|
*/
|
||||||
|
|
||||||
|
get data() {
|
||||||
|
return {
|
||||||
|
originalMaxAge: this.originalMaxAge
|
||||||
|
, expires: this._expires
|
||||||
|
, secure: this.secure
|
||||||
|
, httpOnly: this.httpOnly
|
||||||
|
, domain: this.domain
|
||||||
|
, path: this.path
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Check if the cookie has a reasonably large max-age.
|
||||||
|
*
|
||||||
|
* @return {Boolean}
|
||||||
|
* @api private
|
||||||
|
*/
|
||||||
|
|
||||||
|
get hasLongExpires() {
|
||||||
|
var week = 604800000;
|
||||||
|
return this.maxAge > (4 * week);
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return a serialized cookie string.
|
||||||
|
*
|
||||||
|
* @return {String}
|
||||||
|
* @api public
|
||||||
|
*/
|
||||||
|
|
||||||
|
serialize: function(name, val){
|
||||||
|
return cookie.serialize(name, val, this.data);
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return JSON representation of this cookie.
|
||||||
|
*
|
||||||
|
* @return {Object}
|
||||||
|
* @api private
|
||||||
|
*/
|
||||||
|
|
||||||
|
toJSON: function(){
|
||||||
|
return this.data;
|
||||||
|
}
|
||||||
|
};
|
||||||
129
node_modules/connect/lib/middleware/session/memory.js
generated
vendored
Normal file
@@ -0,0 +1,129 @@
|
|||||||
|
|
||||||
|
/*!
|
||||||
|
* Connect - session - MemoryStore
|
||||||
|
* Copyright(c) 2010 Sencha Inc.
|
||||||
|
* Copyright(c) 2011 TJ Holowaychuk
|
||||||
|
* MIT Licensed
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Module dependencies.
|
||||||
|
*/
|
||||||
|
|
||||||
|
var Store = require('./store');
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Initialize a new `MemoryStore`.
|
||||||
|
*
|
||||||
|
* @api public
|
||||||
|
*/
|
||||||
|
|
||||||
|
var MemoryStore = module.exports = function MemoryStore() {
|
||||||
|
this.sessions = {};
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Inherit from `Store.prototype`.
|
||||||
|
*/
|
||||||
|
|
||||||
|
MemoryStore.prototype.__proto__ = Store.prototype;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Attempt to fetch session by the given `sid`.
|
||||||
|
*
|
||||||
|
* @param {String} sid
|
||||||
|
* @param {Function} fn
|
||||||
|
* @api public
|
||||||
|
*/
|
||||||
|
|
||||||
|
MemoryStore.prototype.get = function(sid, fn){
|
||||||
|
var self = this;
|
||||||
|
process.nextTick(function(){
|
||||||
|
var expires
|
||||||
|
, sess = self.sessions[sid];
|
||||||
|
if (sess) {
|
||||||
|
sess = JSON.parse(sess);
|
||||||
|
expires = 'string' == typeof sess.cookie.expires
|
||||||
|
? new Date(sess.cookie.expires)
|
||||||
|
: sess.cookie.expires;
|
||||||
|
if (!expires || new Date < expires) {
|
||||||
|
fn(null, sess);
|
||||||
|
} else {
|
||||||
|
self.destroy(sid, fn);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
fn();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Commit the given `sess` object associated with the given `sid`.
|
||||||
|
*
|
||||||
|
* @param {String} sid
|
||||||
|
* @param {Session} sess
|
||||||
|
* @param {Function} fn
|
||||||
|
* @api public
|
||||||
|
*/
|
||||||
|
|
||||||
|
MemoryStore.prototype.set = function(sid, sess, fn){
|
||||||
|
var self = this;
|
||||||
|
process.nextTick(function(){
|
||||||
|
self.sessions[sid] = JSON.stringify(sess);
|
||||||
|
fn && fn();
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Destroy the session associated with the given `sid`.
|
||||||
|
*
|
||||||
|
* @param {String} sid
|
||||||
|
* @api public
|
||||||
|
*/
|
||||||
|
|
||||||
|
MemoryStore.prototype.destroy = function(sid, fn){
|
||||||
|
var self = this;
|
||||||
|
process.nextTick(function(){
|
||||||
|
delete self.sessions[sid];
|
||||||
|
fn && fn();
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Invoke the given callback `fn` with all active sessions.
|
||||||
|
*
|
||||||
|
* @param {Function} fn
|
||||||
|
* @api public
|
||||||
|
*/
|
||||||
|
|
||||||
|
MemoryStore.prototype.all = function(fn){
|
||||||
|
var arr = []
|
||||||
|
, keys = Object.keys(this.sessions);
|
||||||
|
for (var i = 0, len = keys.length; i < len; ++i) {
|
||||||
|
arr.push(this.sessions[keys[i]]);
|
||||||
|
}
|
||||||
|
fn(null, arr);
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Clear all sessions.
|
||||||
|
*
|
||||||
|
* @param {Function} fn
|
||||||
|
* @api public
|
||||||
|
*/
|
||||||
|
|
||||||
|
MemoryStore.prototype.clear = function(fn){
|
||||||
|
this.sessions = {};
|
||||||
|
fn && fn();
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Fetch number of sessions.
|
||||||
|
*
|
||||||
|
* @param {Function} fn
|
||||||
|
* @api public
|
||||||
|
*/
|
||||||
|
|
||||||
|
MemoryStore.prototype.length = function(fn){
|
||||||
|
fn(null, Object.keys(this.sessions).length);
|
||||||
|
};
|
||||||
116
node_modules/connect/lib/middleware/session/session.js
generated
vendored
Normal file
@@ -0,0 +1,116 @@
|
|||||||
|
|
||||||
|
/*!
|
||||||
|
* Connect - session - Session
|
||||||
|
* Copyright(c) 2010 Sencha Inc.
|
||||||
|
* Copyright(c) 2011 TJ Holowaychuk
|
||||||
|
* MIT Licensed
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Module dependencies.
|
||||||
|
*/
|
||||||
|
|
||||||
|
var utils = require('../../utils');
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create a new `Session` with the given request and `data`.
|
||||||
|
*
|
||||||
|
* @param {IncomingRequest} req
|
||||||
|
* @param {Object} data
|
||||||
|
* @api private
|
||||||
|
*/
|
||||||
|
|
||||||
|
var Session = module.exports = function Session(req, data) {
|
||||||
|
Object.defineProperty(this, 'req', { value: req });
|
||||||
|
Object.defineProperty(this, 'id', { value: req.sessionID });
|
||||||
|
if ('object' == typeof data) utils.merge(this, data);
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Update reset `.cookie.maxAge` to prevent
|
||||||
|
* the cookie from expiring when the
|
||||||
|
* session is still active.
|
||||||
|
*
|
||||||
|
* @return {Session} for chaining
|
||||||
|
* @api public
|
||||||
|
*/
|
||||||
|
|
||||||
|
Session.prototype.touch = function(){
|
||||||
|
return this.resetMaxAge();
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Reset `.maxAge` to `.originalMaxAge`.
|
||||||
|
*
|
||||||
|
* @return {Session} for chaining
|
||||||
|
* @api public
|
||||||
|
*/
|
||||||
|
|
||||||
|
Session.prototype.resetMaxAge = function(){
|
||||||
|
this.cookie.maxAge = this.cookie.originalMaxAge;
|
||||||
|
return this;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Save the session data with optional callback `fn(err)`.
|
||||||
|
*
|
||||||
|
* @param {Function} fn
|
||||||
|
* @return {Session} for chaining
|
||||||
|
* @api public
|
||||||
|
*/
|
||||||
|
|
||||||
|
Session.prototype.save = function(fn){
|
||||||
|
this.req.sessionStore.set(this.id, this, fn || function(){});
|
||||||
|
return this;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Re-loads the session data _without_ altering
|
||||||
|
* the maxAge properties. Invokes the callback `fn(err)`,
|
||||||
|
* after which time if no exception has occurred the
|
||||||
|
* `req.session` property will be a new `Session` object,
|
||||||
|
* although representing the same session.
|
||||||
|
*
|
||||||
|
* @param {Function} fn
|
||||||
|
* @return {Session} for chaining
|
||||||
|
* @api public
|
||||||
|
*/
|
||||||
|
|
||||||
|
Session.prototype.reload = function(fn){
|
||||||
|
var req = this.req
|
||||||
|
, store = this.req.sessionStore;
|
||||||
|
store.get(this.id, function(err, sess){
|
||||||
|
if (err) return fn(err);
|
||||||
|
if (!sess) return fn(new Error('failed to load session'));
|
||||||
|
store.createSession(req, sess);
|
||||||
|
fn();
|
||||||
|
});
|
||||||
|
return this;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Destroy `this` session.
|
||||||
|
*
|
||||||
|
* @param {Function} fn
|
||||||
|
* @return {Session} for chaining
|
||||||
|
* @api public
|
||||||
|
*/
|
||||||
|
|
||||||
|
Session.prototype.destroy = function(fn){
|
||||||
|
delete this.req.session;
|
||||||
|
this.req.sessionStore.destroy(this.id, fn);
|
||||||
|
return this;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Regenerate this request's session.
|
||||||
|
*
|
||||||
|
* @param {Function} fn
|
||||||
|
* @return {Session} for chaining
|
||||||
|
* @api public
|
||||||
|
*/
|
||||||
|
|
||||||
|
Session.prototype.regenerate = function(fn){
|
||||||
|
this.req.sessionStore.regenerate(this.req, fn);
|
||||||
|
return this;
|
||||||
|
};
|
||||||
84
node_modules/connect/lib/middleware/session/store.js
generated
vendored
Normal file
@@ -0,0 +1,84 @@
|
|||||||
|
|
||||||
|
/*!
|
||||||
|
* Connect - session - Store
|
||||||
|
* Copyright(c) 2010 Sencha Inc.
|
||||||
|
* Copyright(c) 2011 TJ Holowaychuk
|
||||||
|
* MIT Licensed
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Module dependencies.
|
||||||
|
*/
|
||||||
|
|
||||||
|
var EventEmitter = require('events').EventEmitter
|
||||||
|
, Session = require('./session')
|
||||||
|
, Cookie = require('./cookie');
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Initialize abstract `Store`.
|
||||||
|
*
|
||||||
|
* @api private
|
||||||
|
*/
|
||||||
|
|
||||||
|
var Store = module.exports = function Store(options){};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Inherit from `EventEmitter.prototype`.
|
||||||
|
*/
|
||||||
|
|
||||||
|
Store.prototype.__proto__ = EventEmitter.prototype;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Re-generate the given requests's session.
|
||||||
|
*
|
||||||
|
* @param {IncomingRequest} req
|
||||||
|
* @return {Function} fn
|
||||||
|
* @api public
|
||||||
|
*/
|
||||||
|
|
||||||
|
Store.prototype.regenerate = function(req, fn){
|
||||||
|
var self = this;
|
||||||
|
this.destroy(req.sessionID, function(err){
|
||||||
|
self.generate(req);
|
||||||
|
fn(err);
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Load a `Session` instance via the given `sid`
|
||||||
|
* and invoke the callback `fn(err, sess)`.
|
||||||
|
*
|
||||||
|
* @param {String} sid
|
||||||
|
* @param {Function} fn
|
||||||
|
* @api public
|
||||||
|
*/
|
||||||
|
|
||||||
|
Store.prototype.load = function(sid, fn){
|
||||||
|
var self = this;
|
||||||
|
this.get(sid, function(err, sess){
|
||||||
|
if (err) return fn(err);
|
||||||
|
if (!sess) return fn();
|
||||||
|
var req = { sessionID: sid, sessionStore: self };
|
||||||
|
sess = self.createSession(req, sess);
|
||||||
|
fn(null, sess);
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create session from JSON `sess` data.
|
||||||
|
*
|
||||||
|
* @param {IncomingRequest} req
|
||||||
|
* @param {Object} sess
|
||||||
|
* @return {Session}
|
||||||
|
* @api private
|
||||||
|
*/
|
||||||
|
|
||||||
|
Store.prototype.createSession = function(req, sess){
|
||||||
|
var expires = sess.cookie.expires
|
||||||
|
, orig = sess.cookie.originalMaxAge;
|
||||||
|
sess.cookie = new Cookie(sess.cookie);
|
||||||
|
if ('string' == typeof expires) sess.cookie.expires = new Date(expires);
|
||||||
|
sess.cookie.originalMaxAge = orig;
|
||||||
|
req.session = new Session(req, sess);
|
||||||
|
return req.session;
|
||||||
|
};
|
||||||
95
node_modules/connect/lib/middleware/static.js
generated
vendored
Normal file
@@ -0,0 +1,95 @@
|
|||||||
|
/*!
|
||||||
|
* Connect - static
|
||||||
|
* Copyright(c) 2010 Sencha Inc.
|
||||||
|
* Copyright(c) 2011 TJ Holowaychuk
|
||||||
|
* MIT Licensed
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Module dependencies.
|
||||||
|
*/
|
||||||
|
|
||||||
|
var send = require('send')
|
||||||
|
, utils = require('../utils')
|
||||||
|
, parse = utils.parseUrl
|
||||||
|
, url = require('url');
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Static:
|
||||||
|
*
|
||||||
|
* Static file server with the given `root` path.
|
||||||
|
*
|
||||||
|
* Examples:
|
||||||
|
*
|
||||||
|
* var oneDay = 86400000;
|
||||||
|
*
|
||||||
|
* connect()
|
||||||
|
* .use(connect.static(__dirname + '/public'))
|
||||||
|
*
|
||||||
|
* connect()
|
||||||
|
* .use(connect.static(__dirname + '/public', { maxAge: oneDay }))
|
||||||
|
*
|
||||||
|
* Options:
|
||||||
|
*
|
||||||
|
* - `maxAge` Browser cache maxAge in milliseconds. defaults to 0
|
||||||
|
* - `hidden` Allow transfer of hidden files. defaults to false
|
||||||
|
* - `redirect` Redirect to trailing "/" when the pathname is a dir. defaults to true
|
||||||
|
* - `index` Default file name, defaults to 'index.html'
|
||||||
|
*
|
||||||
|
* @param {String} root
|
||||||
|
* @param {Object} options
|
||||||
|
* @return {Function}
|
||||||
|
* @api public
|
||||||
|
*/
|
||||||
|
|
||||||
|
exports = module.exports = function static(root, options){
|
||||||
|
options = options || {};
|
||||||
|
|
||||||
|
// root required
|
||||||
|
if (!root) throw new Error('static() root path required');
|
||||||
|
|
||||||
|
// default redirect
|
||||||
|
var redirect = false !== options.redirect;
|
||||||
|
|
||||||
|
return function static(req, res, next) {
|
||||||
|
if ('GET' != req.method && 'HEAD' != req.method) return next();
|
||||||
|
var path = parse(req).pathname;
|
||||||
|
var pause = utils.pause(req);
|
||||||
|
|
||||||
|
function resume() {
|
||||||
|
next();
|
||||||
|
pause.resume();
|
||||||
|
}
|
||||||
|
|
||||||
|
function directory() {
|
||||||
|
if (!redirect) return resume();
|
||||||
|
var pathname = url.parse(req.originalUrl).pathname;
|
||||||
|
res.statusCode = 301;
|
||||||
|
res.setHeader('Location', pathname + '/');
|
||||||
|
res.end('Redirecting to ' + utils.escape(pathname) + '/');
|
||||||
|
}
|
||||||
|
|
||||||
|
function error(err) {
|
||||||
|
if (404 == err.status) return resume();
|
||||||
|
next(err);
|
||||||
|
}
|
||||||
|
|
||||||
|
send(req, path)
|
||||||
|
.maxage(options.maxAge || 0)
|
||||||
|
.root(root)
|
||||||
|
.index(options.index || 'index.html')
|
||||||
|
.hidden(options.hidden)
|
||||||
|
.on('error', error)
|
||||||
|
.on('directory', directory)
|
||||||
|
.pipe(res);
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Expose mime module.
|
||||||
|
*
|
||||||
|
* If you wish to extend the mime table use this
|
||||||
|
* reference to the "mime" module in the npm registry.
|
||||||
|
*/
|
||||||
|
|
||||||
|
exports.mime = send.mime;
|
||||||
231
node_modules/connect/lib/middleware/staticCache.js
generated
vendored
Normal file
@@ -0,0 +1,231 @@
|
|||||||
|
|
||||||
|
/*!
|
||||||
|
* Connect - staticCache
|
||||||
|
* Copyright(c) 2011 Sencha Inc.
|
||||||
|
* MIT Licensed
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Module dependencies.
|
||||||
|
*/
|
||||||
|
|
||||||
|
var utils = require('../utils')
|
||||||
|
, Cache = require('../cache')
|
||||||
|
, fresh = require('fresh');
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Static cache:
|
||||||
|
*
|
||||||
|
* Enables a memory cache layer on top of
|
||||||
|
* the `static()` middleware, serving popular
|
||||||
|
* static files.
|
||||||
|
*
|
||||||
|
* By default a maximum of 128 objects are
|
||||||
|
* held in cache, with a max of 256k each,
|
||||||
|
* totalling ~32mb.
|
||||||
|
*
|
||||||
|
* A Least-Recently-Used (LRU) cache algo
|
||||||
|
* is implemented through the `Cache` object,
|
||||||
|
* simply rotating cache objects as they are
|
||||||
|
* hit. This means that increasingly popular
|
||||||
|
* objects maintain their positions while
|
||||||
|
* others get shoved out of the stack and
|
||||||
|
* garbage collected.
|
||||||
|
*
|
||||||
|
* Benchmarks:
|
||||||
|
*
|
||||||
|
* static(): 2700 rps
|
||||||
|
* node-static: 5300 rps
|
||||||
|
* static() + staticCache(): 7500 rps
|
||||||
|
*
|
||||||
|
* Options:
|
||||||
|
*
|
||||||
|
* - `maxObjects` max cache objects [128]
|
||||||
|
* - `maxLength` max cache object length 256kb
|
||||||
|
*
|
||||||
|
* @param {Object} options
|
||||||
|
* @return {Function}
|
||||||
|
* @api public
|
||||||
|
*/
|
||||||
|
|
||||||
|
module.exports = function staticCache(options){
|
||||||
|
var options = options || {}
|
||||||
|
, cache = new Cache(options.maxObjects || 128)
|
||||||
|
, maxlen = options.maxLength || 1024 * 256;
|
||||||
|
|
||||||
|
console.warn('connect.staticCache() is deprecated and will be removed in 3.0');
|
||||||
|
console.warn('use varnish or similar reverse proxy caches.');
|
||||||
|
|
||||||
|
return function staticCache(req, res, next){
|
||||||
|
var key = cacheKey(req)
|
||||||
|
, ranges = req.headers.range
|
||||||
|
, hasCookies = req.headers.cookie
|
||||||
|
, hit = cache.get(key);
|
||||||
|
|
||||||
|
// cache static
|
||||||
|
// TODO: change from staticCache() -> cache()
|
||||||
|
// and make this work for any request
|
||||||
|
req.on('static', function(stream){
|
||||||
|
var headers = res._headers
|
||||||
|
, cc = utils.parseCacheControl(headers['cache-control'] || '')
|
||||||
|
, contentLength = headers['content-length']
|
||||||
|
, hit;
|
||||||
|
|
||||||
|
// dont cache set-cookie responses
|
||||||
|
if (headers['set-cookie']) return hasCookies = true;
|
||||||
|
|
||||||
|
// dont cache when cookies are present
|
||||||
|
if (hasCookies) return;
|
||||||
|
|
||||||
|
// ignore larger files
|
||||||
|
if (!contentLength || contentLength > maxlen) return;
|
||||||
|
|
||||||
|
// don't cache partial files
|
||||||
|
if (headers['content-range']) return;
|
||||||
|
|
||||||
|
// dont cache items we shouldn't be
|
||||||
|
// TODO: real support for must-revalidate / no-cache
|
||||||
|
if ( cc['no-cache']
|
||||||
|
|| cc['no-store']
|
||||||
|
|| cc['private']
|
||||||
|
|| cc['must-revalidate']) return;
|
||||||
|
|
||||||
|
// if already in cache then validate
|
||||||
|
if (hit = cache.get(key)){
|
||||||
|
if (headers.etag == hit[0].etag) {
|
||||||
|
hit[0].date = new Date;
|
||||||
|
return;
|
||||||
|
} else {
|
||||||
|
cache.remove(key);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// validation notifiactions don't contain a steam
|
||||||
|
if (null == stream) return;
|
||||||
|
|
||||||
|
// add the cache object
|
||||||
|
var arr = [];
|
||||||
|
|
||||||
|
// store the chunks
|
||||||
|
stream.on('data', function(chunk){
|
||||||
|
arr.push(chunk);
|
||||||
|
});
|
||||||
|
|
||||||
|
// flag it as complete
|
||||||
|
stream.on('end', function(){
|
||||||
|
var cacheEntry = cache.add(key);
|
||||||
|
delete headers['x-cache']; // Clean up (TODO: others)
|
||||||
|
cacheEntry.push(200);
|
||||||
|
cacheEntry.push(headers);
|
||||||
|
cacheEntry.push.apply(cacheEntry, arr);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
if (req.method == 'GET' || req.method == 'HEAD') {
|
||||||
|
if (ranges) {
|
||||||
|
next();
|
||||||
|
} else if (!hasCookies && hit && !mustRevalidate(req, hit)) {
|
||||||
|
res.setHeader('X-Cache', 'HIT');
|
||||||
|
respondFromCache(req, res, hit);
|
||||||
|
} else {
|
||||||
|
res.setHeader('X-Cache', 'MISS');
|
||||||
|
next();
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
next();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Respond with the provided cached value.
|
||||||
|
* TODO: Assume 200 code, that's iffy.
|
||||||
|
*
|
||||||
|
* @param {Object} req
|
||||||
|
* @param {Object} res
|
||||||
|
* @param {Object} cacheEntry
|
||||||
|
* @return {String}
|
||||||
|
* @api private
|
||||||
|
*/
|
||||||
|
|
||||||
|
function respondFromCache(req, res, cacheEntry) {
|
||||||
|
var status = cacheEntry[0]
|
||||||
|
, headers = utils.merge({}, cacheEntry[1])
|
||||||
|
, content = cacheEntry.slice(2);
|
||||||
|
|
||||||
|
headers.age = (new Date - new Date(headers.date)) / 1000 || 0;
|
||||||
|
|
||||||
|
switch (req.method) {
|
||||||
|
case 'HEAD':
|
||||||
|
res.writeHead(status, headers);
|
||||||
|
res.end();
|
||||||
|
break;
|
||||||
|
case 'GET':
|
||||||
|
if (utils.conditionalGET(req) && fresh(req.headers, headers)) {
|
||||||
|
headers['content-length'] = 0;
|
||||||
|
res.writeHead(304, headers);
|
||||||
|
res.end();
|
||||||
|
} else {
|
||||||
|
res.writeHead(status, headers);
|
||||||
|
|
||||||
|
function write() {
|
||||||
|
while (content.length) {
|
||||||
|
if (false === res.write(content.shift())) {
|
||||||
|
res.once('drain', write);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
res.end();
|
||||||
|
}
|
||||||
|
|
||||||
|
write();
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
// This should never happen.
|
||||||
|
res.writeHead(500, '');
|
||||||
|
res.end();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Determine whether or not a cached value must be revalidated.
|
||||||
|
*
|
||||||
|
* @param {Object} req
|
||||||
|
* @param {Object} cacheEntry
|
||||||
|
* @return {String}
|
||||||
|
* @api private
|
||||||
|
*/
|
||||||
|
|
||||||
|
function mustRevalidate(req, cacheEntry) {
|
||||||
|
var cacheHeaders = cacheEntry[1]
|
||||||
|
, reqCC = utils.parseCacheControl(req.headers['cache-control'] || '')
|
||||||
|
, cacheCC = utils.parseCacheControl(cacheHeaders['cache-control'] || '')
|
||||||
|
, cacheAge = (new Date - new Date(cacheHeaders.date)) / 1000 || 0;
|
||||||
|
|
||||||
|
if ( cacheCC['no-cache']
|
||||||
|
|| cacheCC['must-revalidate']
|
||||||
|
|| cacheCC['proxy-revalidate']) return true;
|
||||||
|
|
||||||
|
if (reqCC['no-cache']) return true;
|
||||||
|
|
||||||
|
if (null != reqCC['max-age']) return reqCC['max-age'] < cacheAge;
|
||||||
|
|
||||||
|
if (null != cacheCC['max-age']) return cacheCC['max-age'] < cacheAge;
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The key to use in the cache. For now, this is the URL path and query.
|
||||||
|
*
|
||||||
|
* 'http://example.com?key=value' -> '/?key=value'
|
||||||
|
*
|
||||||
|
* @param {Object} req
|
||||||
|
* @return {String}
|
||||||
|
* @api private
|
||||||
|
*/
|
||||||
|
|
||||||
|
function cacheKey(req) {
|
||||||
|
return utils.parseUrl(req).path;
|
||||||
|
}
|
||||||
55
node_modules/connect/lib/middleware/timeout.js
generated
vendored
Normal file
@@ -0,0 +1,55 @@
|
|||||||
|
/*!
|
||||||
|
* Connect - timeout
|
||||||
|
* Ported from https://github.com/LearnBoost/connect-timeout
|
||||||
|
* MIT Licensed
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Module dependencies.
|
||||||
|
*/
|
||||||
|
|
||||||
|
var debug = require('debug')('connect:timeout');
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Timeout:
|
||||||
|
*
|
||||||
|
* Times out the request in `ms`, defaulting to `5000`. The
|
||||||
|
* method `req.clearTimeout()` is added to revert this behaviour
|
||||||
|
* programmatically within your application's middleware, routes, etc.
|
||||||
|
*
|
||||||
|
* The timeout error is passed to `next()` so that you may customize
|
||||||
|
* the response behaviour. This error has the `.timeout` property as
|
||||||
|
* well as `.status == 408`.
|
||||||
|
*
|
||||||
|
* @param {Number} ms
|
||||||
|
* @return {Function}
|
||||||
|
* @api public
|
||||||
|
*/
|
||||||
|
|
||||||
|
module.exports = function timeout(ms) {
|
||||||
|
ms = ms || 5000;
|
||||||
|
|
||||||
|
return function(req, res, next) {
|
||||||
|
var id = setTimeout(function(){
|
||||||
|
req.emit('timeout', ms);
|
||||||
|
}, ms);
|
||||||
|
|
||||||
|
req.on('timeout', function(){
|
||||||
|
if (res.headerSent) return debug('response started, cannot timeout');
|
||||||
|
var err = new Error('Response timeout');
|
||||||
|
err.timeout = ms;
|
||||||
|
err.status = 503;
|
||||||
|
next(err);
|
||||||
|
});
|
||||||
|
|
||||||
|
req.clearTimeout = function(){
|
||||||
|
clearTimeout(id);
|
||||||
|
};
|
||||||
|
|
||||||
|
res.on('header', function(){
|
||||||
|
clearTimeout(id);
|
||||||
|
});
|
||||||
|
|
||||||
|
next();
|
||||||
|
};
|
||||||
|
};
|
||||||
78
node_modules/connect/lib/middleware/urlencoded.js
generated
vendored
Normal file
@@ -0,0 +1,78 @@
|
|||||||
|
|
||||||
|
/*!
|
||||||
|
* Connect - urlencoded
|
||||||
|
* Copyright(c) 2010 Sencha Inc.
|
||||||
|
* Copyright(c) 2011 TJ Holowaychuk
|
||||||
|
* MIT Licensed
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Module dependencies.
|
||||||
|
*/
|
||||||
|
|
||||||
|
var utils = require('../utils')
|
||||||
|
, _limit = require('./limit')
|
||||||
|
, qs = require('qs');
|
||||||
|
|
||||||
|
/**
|
||||||
|
* noop middleware.
|
||||||
|
*/
|
||||||
|
|
||||||
|
function noop(req, res, next) {
|
||||||
|
next();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Urlencoded:
|
||||||
|
*
|
||||||
|
* Parse x-ww-form-urlencoded request bodies,
|
||||||
|
* providing the parsed object as `req.body`.
|
||||||
|
*
|
||||||
|
* Options:
|
||||||
|
*
|
||||||
|
* - `limit` byte limit disabled by default
|
||||||
|
*
|
||||||
|
* @param {Object} options
|
||||||
|
* @return {Function}
|
||||||
|
* @api public
|
||||||
|
*/
|
||||||
|
|
||||||
|
exports = module.exports = function(options){
|
||||||
|
options = options || {};
|
||||||
|
|
||||||
|
var limit = options.limit
|
||||||
|
? _limit(options.limit)
|
||||||
|
: noop;
|
||||||
|
|
||||||
|
return function urlencoded(req, res, next) {
|
||||||
|
if (req._body) return next();
|
||||||
|
req.body = req.body || {};
|
||||||
|
|
||||||
|
if (!utils.hasBody(req)) return next();
|
||||||
|
|
||||||
|
// check Content-Type
|
||||||
|
if ('application/x-www-form-urlencoded' != utils.mime(req)) return next();
|
||||||
|
|
||||||
|
// flag as parsed
|
||||||
|
req._body = true;
|
||||||
|
|
||||||
|
// parse
|
||||||
|
limit(req, res, function(err){
|
||||||
|
if (err) return next(err);
|
||||||
|
var buf = '';
|
||||||
|
req.setEncoding('utf8');
|
||||||
|
req.on('data', function(chunk){ buf += chunk });
|
||||||
|
req.on('end', function(){
|
||||||
|
try {
|
||||||
|
req.body = buf.length
|
||||||
|
? qs.parse(buf, options)
|
||||||
|
: {};
|
||||||
|
next();
|
||||||
|
} catch (err){
|
||||||
|
err.body = buf;
|
||||||
|
next(err);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
};
|
||||||
40
node_modules/connect/lib/middleware/vhost.js
generated
vendored
Normal file
@@ -0,0 +1,40 @@
|
|||||||
|
|
||||||
|
/*!
|
||||||
|
* Connect - vhost
|
||||||
|
* Copyright(c) 2010 Sencha Inc.
|
||||||
|
* Copyright(c) 2011 TJ Holowaychuk
|
||||||
|
* MIT Licensed
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Vhost:
|
||||||
|
*
|
||||||
|
* Setup vhost for the given `hostname` and `server`.
|
||||||
|
*
|
||||||
|
* connect()
|
||||||
|
* .use(connect.vhost('foo.com', fooApp))
|
||||||
|
* .use(connect.vhost('bar.com', barApp))
|
||||||
|
* .use(connect.vhost('*.com', mainApp))
|
||||||
|
*
|
||||||
|
* The `server` may be a Connect server or
|
||||||
|
* a regular Node `http.Server`.
|
||||||
|
*
|
||||||
|
* @param {String} hostname
|
||||||
|
* @param {Server} server
|
||||||
|
* @return {Function}
|
||||||
|
* @api public
|
||||||
|
*/
|
||||||
|
|
||||||
|
module.exports = function vhost(hostname, server){
|
||||||
|
if (!hostname) throw new Error('vhost hostname required');
|
||||||
|
if (!server) throw new Error('vhost server required');
|
||||||
|
var regexp = new RegExp('^' + hostname.replace(/[^*\w]/g, '\\$&').replace(/[*]/g, '(?:.*?)') + '$', 'i');
|
||||||
|
if (server.onvhost) server.onvhost(hostname);
|
||||||
|
return function vhost(req, res, next){
|
||||||
|
if (!req.headers.host) return next();
|
||||||
|
var host = req.headers.host.split(':')[0];
|
||||||
|
if (!regexp.test(host)) return next();
|
||||||
|
if ('function' == typeof server) return server(req, res, next);
|
||||||
|
server.emit('request', req, res);
|
||||||
|
};
|
||||||
|
};
|
||||||
79
node_modules/connect/lib/patch.js
generated
vendored
Normal file
@@ -0,0 +1,79 @@
|
|||||||
|
|
||||||
|
/*!
|
||||||
|
* Connect
|
||||||
|
* Copyright(c) 2011 TJ Holowaychuk
|
||||||
|
* MIT Licensed
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Module dependencies.
|
||||||
|
*/
|
||||||
|
|
||||||
|
var http = require('http')
|
||||||
|
, res = http.ServerResponse.prototype
|
||||||
|
, setHeader = res.setHeader
|
||||||
|
, _renderHeaders = res._renderHeaders
|
||||||
|
, writeHead = res.writeHead;
|
||||||
|
|
||||||
|
// apply only once
|
||||||
|
|
||||||
|
if (!res._hasConnectPatch) {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Provide a public "header sent" flag
|
||||||
|
* until node does.
|
||||||
|
*
|
||||||
|
* @return {Boolean}
|
||||||
|
* @api public
|
||||||
|
*/
|
||||||
|
|
||||||
|
res.__defineGetter__('headerSent', function(){
|
||||||
|
return this._header;
|
||||||
|
});
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set header `field` to `val`, special-casing
|
||||||
|
* the `Set-Cookie` field for multiple support.
|
||||||
|
*
|
||||||
|
* @param {String} field
|
||||||
|
* @param {String} val
|
||||||
|
* @api public
|
||||||
|
*/
|
||||||
|
|
||||||
|
res.setHeader = function(field, val){
|
||||||
|
var key = field.toLowerCase()
|
||||||
|
, prev;
|
||||||
|
|
||||||
|
// special-case Set-Cookie
|
||||||
|
if (this._headers && 'set-cookie' == key) {
|
||||||
|
if (prev = this.getHeader(field)) {
|
||||||
|
val = Array.isArray(prev)
|
||||||
|
? prev.concat(val)
|
||||||
|
: [prev, val];
|
||||||
|
}
|
||||||
|
// charset
|
||||||
|
} else if ('content-type' == key && this.charset) {
|
||||||
|
val += '; charset=' + this.charset;
|
||||||
|
}
|
||||||
|
|
||||||
|
return setHeader.call(this, field, val);
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Proxy to emit "header" event.
|
||||||
|
*/
|
||||||
|
|
||||||
|
res._renderHeaders = function(){
|
||||||
|
if (!this._emittedHeader) this.emit('header');
|
||||||
|
this._emittedHeader = true;
|
||||||
|
return _renderHeaders.call(this);
|
||||||
|
};
|
||||||
|
|
||||||
|
res.writeHead = function(){
|
||||||
|
if (!this._emittedHeader) this.emit('header');
|
||||||
|
this._emittedHeader = true;
|
||||||
|
return writeHead.apply(this, arguments);
|
||||||
|
};
|
||||||
|
|
||||||
|
res._hasConnectPatch = true;
|
||||||
|
}
|
||||||
230
node_modules/connect/lib/proto.js
generated
vendored
Normal file
@@ -0,0 +1,230 @@
|
|||||||
|
|
||||||
|
/*!
|
||||||
|
* Connect - HTTPServer
|
||||||
|
* Copyright(c) 2010 Sencha Inc.
|
||||||
|
* Copyright(c) 2011 TJ Holowaychuk
|
||||||
|
* MIT Licensed
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Module dependencies.
|
||||||
|
*/
|
||||||
|
|
||||||
|
var http = require('http')
|
||||||
|
, utils = require('./utils')
|
||||||
|
, debug = require('debug')('connect:dispatcher');
|
||||||
|
|
||||||
|
// prototype
|
||||||
|
|
||||||
|
var app = module.exports = {};
|
||||||
|
|
||||||
|
// environment
|
||||||
|
|
||||||
|
var env = process.env.NODE_ENV || 'development';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Utilize the given middleware `handle` to the given `route`,
|
||||||
|
* defaulting to _/_. This "route" is the mount-point for the
|
||||||
|
* middleware, when given a value other than _/_ the middleware
|
||||||
|
* is only effective when that segment is present in the request's
|
||||||
|
* pathname.
|
||||||
|
*
|
||||||
|
* For example if we were to mount a function at _/admin_, it would
|
||||||
|
* be invoked on _/admin_, and _/admin/settings_, however it would
|
||||||
|
* not be invoked for _/_, or _/posts_.
|
||||||
|
*
|
||||||
|
* Examples:
|
||||||
|
*
|
||||||
|
* var app = connect();
|
||||||
|
* app.use(connect.favicon());
|
||||||
|
* app.use(connect.logger());
|
||||||
|
* app.use(connect.static(__dirname + '/public'));
|
||||||
|
*
|
||||||
|
* If we wanted to prefix static files with _/public_, we could
|
||||||
|
* "mount" the `static()` middleware:
|
||||||
|
*
|
||||||
|
* app.use('/public', connect.static(__dirname + '/public'));
|
||||||
|
*
|
||||||
|
* This api is chainable, so the following is valid:
|
||||||
|
*
|
||||||
|
* connect()
|
||||||
|
* .use(connect.favicon())
|
||||||
|
* .use(connect.logger())
|
||||||
|
* .use(connect.static(__dirname + '/public'))
|
||||||
|
* .listen(3000);
|
||||||
|
*
|
||||||
|
* @param {String|Function|Server} route, callback or server
|
||||||
|
* @param {Function|Server} callback or server
|
||||||
|
* @return {Server} for chaining
|
||||||
|
* @api public
|
||||||
|
*/
|
||||||
|
|
||||||
|
app.use = function(route, fn){
|
||||||
|
// default route to '/'
|
||||||
|
if ('string' != typeof route) {
|
||||||
|
fn = route;
|
||||||
|
route = '/';
|
||||||
|
}
|
||||||
|
|
||||||
|
// wrap sub-apps
|
||||||
|
if ('function' == typeof fn.handle) {
|
||||||
|
var server = fn;
|
||||||
|
fn.route = route;
|
||||||
|
fn = function(req, res, next){
|
||||||
|
server.handle(req, res, next);
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
// wrap vanilla http.Servers
|
||||||
|
if (fn instanceof http.Server) {
|
||||||
|
fn = fn.listeners('request')[0];
|
||||||
|
}
|
||||||
|
|
||||||
|
// strip trailing slash
|
||||||
|
if ('/' == route[route.length - 1]) {
|
||||||
|
route = route.slice(0, -1);
|
||||||
|
}
|
||||||
|
|
||||||
|
// add the middleware
|
||||||
|
debug('use %s %s', route || '/', fn.name || 'anonymous');
|
||||||
|
this.stack.push({ route: route, handle: fn });
|
||||||
|
|
||||||
|
return this;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Handle server requests, punting them down
|
||||||
|
* the middleware stack.
|
||||||
|
*
|
||||||
|
* @api private
|
||||||
|
*/
|
||||||
|
|
||||||
|
app.handle = function(req, res, out) {
|
||||||
|
var stack = this.stack
|
||||||
|
, fqdn = ~req.url.indexOf('://')
|
||||||
|
, removed = ''
|
||||||
|
, slashAdded = false
|
||||||
|
, index = 0;
|
||||||
|
|
||||||
|
function next(err) {
|
||||||
|
var layer, path, status, c;
|
||||||
|
|
||||||
|
if (slashAdded) {
|
||||||
|
req.url = req.url.substr(1);
|
||||||
|
slashAdded = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
req.url = removed + req.url;
|
||||||
|
req.originalUrl = req.originalUrl || req.url;
|
||||||
|
removed = '';
|
||||||
|
|
||||||
|
// next callback
|
||||||
|
layer = stack[index++];
|
||||||
|
|
||||||
|
// all done
|
||||||
|
if (!layer || res.headerSent) {
|
||||||
|
// delegate to parent
|
||||||
|
if (out) return out(err);
|
||||||
|
|
||||||
|
// unhandled error
|
||||||
|
if (err) {
|
||||||
|
// default to 500
|
||||||
|
if (res.statusCode < 400) res.statusCode = 500;
|
||||||
|
debug('default %s', res.statusCode);
|
||||||
|
|
||||||
|
// respect err.status
|
||||||
|
if (err.status) res.statusCode = err.status;
|
||||||
|
|
||||||
|
// production gets a basic error message
|
||||||
|
var msg = 'production' == env
|
||||||
|
? http.STATUS_CODES[res.statusCode]
|
||||||
|
: err.stack || err.toString();
|
||||||
|
|
||||||
|
// log to stderr in a non-test env
|
||||||
|
if ('test' != env) console.error(err.stack || err.toString());
|
||||||
|
if (res.headerSent) return req.socket.destroy();
|
||||||
|
res.setHeader('Content-Type', 'text/plain');
|
||||||
|
res.setHeader('Content-Length', Buffer.byteLength(msg));
|
||||||
|
if ('HEAD' == req.method) return res.end();
|
||||||
|
res.end(msg);
|
||||||
|
} else {
|
||||||
|
debug('default 404');
|
||||||
|
res.statusCode = 404;
|
||||||
|
res.setHeader('Content-Type', 'text/plain');
|
||||||
|
if ('HEAD' == req.method) return res.end();
|
||||||
|
res.end('Cannot ' + req.method + ' ' + utils.escape(req.originalUrl));
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
path = utils.parseUrl(req).pathname;
|
||||||
|
if (undefined == path) path = '/';
|
||||||
|
|
||||||
|
// skip this layer if the route doesn't match.
|
||||||
|
if (0 != path.toLowerCase().indexOf(layer.route.toLowerCase())) return next(err);
|
||||||
|
|
||||||
|
c = path[layer.route.length];
|
||||||
|
if (c && '/' != c && '.' != c) return next(err);
|
||||||
|
|
||||||
|
// Call the layer handler
|
||||||
|
// Trim off the part of the url that matches the route
|
||||||
|
removed = layer.route;
|
||||||
|
req.url = req.url.substr(removed.length);
|
||||||
|
|
||||||
|
// Ensure leading slash
|
||||||
|
if (!fqdn && '/' != req.url[0]) {
|
||||||
|
req.url = '/' + req.url;
|
||||||
|
slashAdded = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
debug('%s', layer.handle.name || 'anonymous');
|
||||||
|
var arity = layer.handle.length;
|
||||||
|
if (err) {
|
||||||
|
if (arity === 4) {
|
||||||
|
layer.handle(err, req, res, next);
|
||||||
|
} else {
|
||||||
|
next(err);
|
||||||
|
}
|
||||||
|
} else if (arity < 4) {
|
||||||
|
layer.handle(req, res, next);
|
||||||
|
} else {
|
||||||
|
next();
|
||||||
|
}
|
||||||
|
} catch (e) {
|
||||||
|
next(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
next();
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Listen for connections.
|
||||||
|
*
|
||||||
|
* This method takes the same arguments
|
||||||
|
* as node's `http.Server#listen()`.
|
||||||
|
*
|
||||||
|
* HTTP and HTTPS:
|
||||||
|
*
|
||||||
|
* If you run your application both as HTTP
|
||||||
|
* and HTTPS you may wrap them individually,
|
||||||
|
* since your Connect "server" is really just
|
||||||
|
* a JavaScript `Function`.
|
||||||
|
*
|
||||||
|
* var connect = require('connect')
|
||||||
|
* , http = require('http')
|
||||||
|
* , https = require('https');
|
||||||
|
*
|
||||||
|
* var app = connect();
|
||||||
|
*
|
||||||
|
* http.createServer(app).listen(80);
|
||||||
|
* https.createServer(options, app).listen(443);
|
||||||
|
*
|
||||||
|
* @return {http.Server}
|
||||||
|
* @api public
|
||||||
|
*/
|
||||||
|
|
||||||
|
app.listen = function(){
|
||||||
|
var server = http.createServer(this);
|
||||||
|
return server.listen.apply(server, arguments);
|
||||||
|
};
|
||||||
81
node_modules/connect/lib/public/directory.html
generated
vendored
Normal file
@@ -0,0 +1,81 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
<meta charset='utf-8'>
|
||||||
|
<title>listing directory {directory}</title>
|
||||||
|
<style>{style}</style>
|
||||||
|
<script>
|
||||||
|
function $(id){
|
||||||
|
var el = 'string' == typeof id
|
||||||
|
? document.getElementById(id)
|
||||||
|
: id;
|
||||||
|
|
||||||
|
el.on = function(event, fn){
|
||||||
|
if ('content loaded' == event) {
|
||||||
|
event = window.attachEvent ? "load" : "DOMContentLoaded";
|
||||||
|
}
|
||||||
|
el.addEventListener
|
||||||
|
? el.addEventListener(event, fn, false)
|
||||||
|
: el.attachEvent("on" + event, fn);
|
||||||
|
};
|
||||||
|
|
||||||
|
el.all = function(selector){
|
||||||
|
return $(el.querySelectorAll(selector));
|
||||||
|
};
|
||||||
|
|
||||||
|
el.each = function(fn){
|
||||||
|
for (var i = 0, len = el.length; i < len; ++i) {
|
||||||
|
fn($(el[i]), i);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
el.getClasses = function(){
|
||||||
|
return this.getAttribute('class').split(/\s+/);
|
||||||
|
};
|
||||||
|
|
||||||
|
el.addClass = function(name){
|
||||||
|
var classes = this.getAttribute('class');
|
||||||
|
el.setAttribute('class', classes
|
||||||
|
? classes + ' ' + name
|
||||||
|
: name);
|
||||||
|
};
|
||||||
|
|
||||||
|
el.removeClass = function(name){
|
||||||
|
var classes = this.getClasses().filter(function(curr){
|
||||||
|
return curr != name;
|
||||||
|
});
|
||||||
|
this.setAttribute('class', classes);
|
||||||
|
};
|
||||||
|
|
||||||
|
return el;
|
||||||
|
}
|
||||||
|
|
||||||
|
function search() {
|
||||||
|
var str = $('search').value
|
||||||
|
, links = $('files').all('a');
|
||||||
|
|
||||||
|
links.each(function(link){
|
||||||
|
var text = link.textContent;
|
||||||
|
|
||||||
|
if ('..' == text) return;
|
||||||
|
if (str.length && ~text.indexOf(str)) {
|
||||||
|
link.addClass('highlight');
|
||||||
|
} else {
|
||||||
|
link.removeClass('highlight');
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
$(window).on('content loaded', function(){
|
||||||
|
$('search').on('keyup', search);
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
</head>
|
||||||
|
<body class="directory">
|
||||||
|
<input id="search" type="text" placeholder="Search" autocomplete="off" />
|
||||||
|
<div id="wrapper">
|
||||||
|
<h1>{linked-path}</h1>
|
||||||
|
{files}
|
||||||
|
</div>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
14
node_modules/connect/lib/public/error.html
generated
vendored
Normal file
@@ -0,0 +1,14 @@
|
|||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
<meta charset='utf-8'>
|
||||||
|
<title>{error}</title>
|
||||||
|
<style>{style}</style>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<div id="wrapper">
|
||||||
|
<h1>{title}</h1>
|
||||||
|
<h2><em>{statusCode}</em> {error}</h2>
|
||||||
|
<ul id="stacktrace">{stack}</ul>
|
||||||
|
</div>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
BIN
node_modules/connect/lib/public/favicon.ico
generated
vendored
Normal file
|
After Width: | Height: | Size: 1.4 KiB |
BIN
node_modules/connect/lib/public/icons/page.png
generated
vendored
Normal file
|
After Width: | Height: | Size: 635 B |
BIN
node_modules/connect/lib/public/icons/page_add.png
generated
vendored
Normal file
|
After Width: | Height: | Size: 739 B |
BIN
node_modules/connect/lib/public/icons/page_attach.png
generated
vendored
Normal file
|
After Width: | Height: | Size: 794 B |
BIN
node_modules/connect/lib/public/icons/page_code.png
generated
vendored
Normal file
|
After Width: | Height: | Size: 818 B |
BIN
node_modules/connect/lib/public/icons/page_copy.png
generated
vendored
Normal file
|
After Width: | Height: | Size: 663 B |
BIN
node_modules/connect/lib/public/icons/page_delete.png
generated
vendored
Normal file
|
After Width: | Height: | Size: 740 B |
BIN
node_modules/connect/lib/public/icons/page_edit.png
generated
vendored
Normal file
|
After Width: | Height: | Size: 807 B |
BIN
node_modules/connect/lib/public/icons/page_error.png
generated
vendored
Normal file
|
After Width: | Height: | Size: 793 B |
BIN
node_modules/connect/lib/public/icons/page_excel.png
generated
vendored
Normal file
|
After Width: | Height: | Size: 817 B |
BIN
node_modules/connect/lib/public/icons/page_find.png
generated
vendored
Normal file
|
After Width: | Height: | Size: 879 B |
BIN
node_modules/connect/lib/public/icons/page_gear.png
generated
vendored
Normal file
|
After Width: | Height: | Size: 833 B |
BIN
node_modules/connect/lib/public/icons/page_go.png
generated
vendored
Normal file
|
After Width: | Height: | Size: 779 B |
BIN
node_modules/connect/lib/public/icons/page_green.png
generated
vendored
Normal file
|
After Width: | Height: | Size: 621 B |
BIN
node_modules/connect/lib/public/icons/page_key.png
generated
vendored
Normal file
|
After Width: | Height: | Size: 801 B |
BIN
node_modules/connect/lib/public/icons/page_lightning.png
generated
vendored
Normal file
|
After Width: | Height: | Size: 839 B |
BIN
node_modules/connect/lib/public/icons/page_link.png
generated
vendored
Normal file
|
After Width: | Height: | Size: 830 B |
BIN
node_modules/connect/lib/public/icons/page_paintbrush.png
generated
vendored
Normal file
|
After Width: | Height: | Size: 813 B |
BIN
node_modules/connect/lib/public/icons/page_paste.png
generated
vendored
Normal file
|
After Width: | Height: | Size: 703 B |
BIN
node_modules/connect/lib/public/icons/page_red.png
generated
vendored
Normal file
|
After Width: | Height: | Size: 641 B |
BIN
node_modules/connect/lib/public/icons/page_refresh.png
generated
vendored
Normal file
|
After Width: | Height: | Size: 858 B |
BIN
node_modules/connect/lib/public/icons/page_save.png
generated
vendored
Normal file
|
After Width: | Height: | Size: 774 B |
BIN
node_modules/connect/lib/public/icons/page_white.png
generated
vendored
Normal file
|
After Width: | Height: | Size: 294 B |
BIN
node_modules/connect/lib/public/icons/page_white_acrobat.png
generated
vendored
Normal file
|
After Width: | Height: | Size: 591 B |
BIN
node_modules/connect/lib/public/icons/page_white_actionscript.png
generated
vendored
Normal file
|
After Width: | Height: | Size: 664 B |
BIN
node_modules/connect/lib/public/icons/page_white_add.png
generated
vendored
Normal file
|
After Width: | Height: | Size: 512 B |
BIN
node_modules/connect/lib/public/icons/page_white_c.png
generated
vendored
Normal file
|
After Width: | Height: | Size: 587 B |
BIN
node_modules/connect/lib/public/icons/page_white_camera.png
generated
vendored
Normal file
|
After Width: | Height: | Size: 656 B |
BIN
node_modules/connect/lib/public/icons/page_white_cd.png
generated
vendored
Normal file
|
After Width: | Height: | Size: 666 B |
BIN
node_modules/connect/lib/public/icons/page_white_code.png
generated
vendored
Normal file
|
After Width: | Height: | Size: 603 B |
BIN
node_modules/connect/lib/public/icons/page_white_code_red.png
generated
vendored
Normal file
|
After Width: | Height: | Size: 587 B |
BIN
node_modules/connect/lib/public/icons/page_white_coldfusion.png
generated
vendored
Normal file
|
After Width: | Height: | Size: 592 B |
BIN
node_modules/connect/lib/public/icons/page_white_compressed.png
generated
vendored
Normal file
|
After Width: | Height: | Size: 724 B |
BIN
node_modules/connect/lib/public/icons/page_white_copy.png
generated
vendored
Normal file
|
After Width: | Height: | Size: 309 B |
BIN
node_modules/connect/lib/public/icons/page_white_cplusplus.png
generated
vendored
Normal file
|
After Width: | Height: | Size: 621 B |
BIN
node_modules/connect/lib/public/icons/page_white_csharp.png
generated
vendored
Normal file
|
After Width: | Height: | Size: 700 B |
BIN
node_modules/connect/lib/public/icons/page_white_cup.png
generated
vendored
Normal file
|
After Width: | Height: | Size: 639 B |
BIN
node_modules/connect/lib/public/icons/page_white_database.png
generated
vendored
Normal file
|
After Width: | Height: | Size: 579 B |
BIN
node_modules/connect/lib/public/icons/page_white_delete.png
generated
vendored
Normal file
|
After Width: | Height: | Size: 536 B |
BIN
node_modules/connect/lib/public/icons/page_white_dvd.png
generated
vendored
Normal file
|
After Width: | Height: | Size: 638 B |
BIN
node_modules/connect/lib/public/icons/page_white_edit.png
generated
vendored
Normal file
|
After Width: | Height: | Size: 618 B |
BIN
node_modules/connect/lib/public/icons/page_white_error.png
generated
vendored
Normal file
|
After Width: | Height: | Size: 623 B |
BIN
node_modules/connect/lib/public/icons/page_white_excel.png
generated
vendored
Normal file
|
After Width: | Height: | Size: 663 B |
BIN
node_modules/connect/lib/public/icons/page_white_find.png
generated
vendored
Normal file
|
After Width: | Height: | Size: 676 B |
BIN
node_modules/connect/lib/public/icons/page_white_flash.png
generated
vendored
Normal file
|
After Width: | Height: | Size: 582 B |
BIN
node_modules/connect/lib/public/icons/page_white_freehand.png
generated
vendored
Normal file
|
After Width: | Height: | Size: 639 B |
BIN
node_modules/connect/lib/public/icons/page_white_gear.png
generated
vendored
Normal file
|
After Width: | Height: | Size: 402 B |
BIN
node_modules/connect/lib/public/icons/page_white_get.png
generated
vendored
Normal file
|
After Width: | Height: | Size: 516 B |
BIN
node_modules/connect/lib/public/icons/page_white_go.png
generated
vendored
Normal file
|
After Width: | Height: | Size: 612 B |
BIN
node_modules/connect/lib/public/icons/page_white_h.png
generated
vendored
Normal file
|
After Width: | Height: | Size: 603 B |
BIN
node_modules/connect/lib/public/icons/page_white_horizontal.png
generated
vendored
Normal file
|
After Width: | Height: | Size: 296 B |
BIN
node_modules/connect/lib/public/icons/page_white_key.png
generated
vendored
Normal file
|
After Width: | Height: | Size: 616 B |
BIN
node_modules/connect/lib/public/icons/page_white_lightning.png
generated
vendored
Normal file
|
After Width: | Height: | Size: 669 B |
BIN
node_modules/connect/lib/public/icons/page_white_link.png
generated
vendored
Normal file
|
After Width: | Height: | Size: 614 B |
BIN
node_modules/connect/lib/public/icons/page_white_magnify.png
generated
vendored
Normal file
|
After Width: | Height: | Size: 554 B |
BIN
node_modules/connect/lib/public/icons/page_white_medal.png
generated
vendored
Normal file
|
After Width: | Height: | Size: 706 B |
BIN
node_modules/connect/lib/public/icons/page_white_office.png
generated
vendored
Normal file
|
After Width: | Height: | Size: 779 B |