Added node modules

This commit is contained in:
John Crepezzi 2012-02-06 14:09:01 -05:00
parent ca9d4c18f7
commit d1e0644a4e
575 changed files with 77900 additions and 6 deletions

1
.gitignore vendored
View File

@ -1,5 +1,4 @@
npm-debug.log
node_modules
*.swp
*.swo
data

View File

@ -24,11 +24,8 @@
},
"storage": {
"type": "redis",
"host": "localhost",
"port": 6379,
"db": 2,
"expire": 2592000
"type": "file",
"path": "./data"
},
"documents": {

1
node_modules/.bin/_mocha generated vendored Symbolic link
View File

@ -0,0 +1 @@
../mocha/bin/_mocha

1
node_modules/.bin/mocha generated vendored Symbolic link
View File

@ -0,0 +1 @@
../mocha/bin/mocha

1
node_modules/.bin/uglifyjs generated vendored Symbolic link
View File

@ -0,0 +1 @@
../uglify-js/bin/uglifyjs

11
node_modules/connect/.npmignore generated vendored Normal file
View File

@ -0,0 +1,11 @@
*.markdown
*.md
.git*
Makefile
benchmarks/
docs/
examples/
install.sh
support/
test/
.DS_Store

24
node_modules/connect/LICENSE generated vendored Normal file
View 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.

2
node_modules/connect/index.js generated vendored Normal file
View File

@ -0,0 +1,2 @@
module.exports = require('./lib/connect');

81
node_modules/connect/lib/cache.js generated vendored Normal file
View 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, invalid LRU
if (len > this.limit) this.remove(this.keys.shift());
var arr = this.store[key] = [];
arr.createdAt = new Date;
return arr;
};

106
node_modules/connect/lib/connect.js generated vendored Normal file
View File

@ -0,0 +1,106 @@
/*!
* Connect
* Copyright(c) 2010 Sencha Inc.
* Copyright(c) 2011 TJ Holowaychuk
* MIT Licensed
*/
/**
* Module dependencies.
*/
var HTTPServer = require('./http').Server
, HTTPSServer = require('./https').Server
, fs = require('fs');
// node patches
require('./patch');
// expose createServer() as the module
exports = module.exports = createServer;
/**
* Framework version.
*/
exports.version = '1.8.5';
/**
* Initialize a new `connect.HTTPServer` with the middleware
* passed to this function. When an object is passed _first_,
* we assume these are the tls options, and return a `connect.HTTPSServer`.
*
* Examples:
*
* An example HTTP server, accepting several middleware.
*
* var server = connect.createServer(
* connect.logger()
* , connect.static(__dirname + '/public')
* );
*
* An HTTPS server, utilizing the same middleware as above.
*
* var server = connect.createServer(
* { key: key, cert: cert }
* , connect.logger()
* , connect.static(__dirname + '/public')
* );
*
* Alternatively with connect 1.0 we may omit `createServer()`.
*
* connect(
* connect.logger()
* , connect.static(__dirname + '/public')
* ).listen(3000);
*
* @param {Object|Function} ...
* @return {Server}
* @api public
*/
function createServer() {
if ('object' == typeof arguments[0]) {
return new HTTPSServer(arguments[0], Array.prototype.slice.call(arguments, 1));
} else {
return new HTTPServer(Array.prototype.slice.call(arguments));
}
};
// support connect.createServer()
exports.createServer = createServer;
// auto-load getters
exports.middleware = {};
/**
* Auto-load bundled middleware with getters.
*/
fs.readdirSync(__dirname + '/middleware').forEach(function(filename){
if (/\.js$/.test(filename)) {
var name = filename.substr(0, filename.lastIndexOf('.'));
exports.middleware.__defineGetter__(name, function(){
return require('./middleware/' + name);
});
}
});
// expose utils
exports.utils = require('./utils');
// expose getters as first-class exports
exports.utils.merge(exports, exports.middleware);
// expose constructors
exports.HTTPServer = HTTPServer;
exports.HTTPSServer = HTTPSServer;

217
node_modules/connect/lib/http.js generated vendored Normal file
View File

@ -0,0 +1,217 @@
/*!
* Connect - HTTPServer
* Copyright(c) 2010 Sencha Inc.
* Copyright(c) 2011 TJ Holowaychuk
* MIT Licensed
*/
/**
* Module dependencies.
*/
var http = require('http')
, parse = require('url').parse
, assert = require('assert');
// environment
var env = process.env.NODE_ENV || 'development';
/**
* Initialize a new `Server` with the given `middleware`.
*
* Examples:
*
* var server = connect.createServer(
* connect.favicon()
* , connect.logger()
* , connect.static(__dirname + '/public')
* );
*
* @params {Array} middleware
* @return {Server}
* @api public
*/
var Server = exports.Server = function HTTPServer(middleware) {
this.stack = [];
middleware.forEach(function(fn){
this.use(fn);
}, this);
http.Server.call(this, this.handle);
};
/**
* Inherit from `http.Server.prototype`.
*/
Server.prototype.__proto__ = http.Server.prototype;
/**
* 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_.
*
* This is effectively the same as passing middleware to `connect.createServer()`,
* however provides a progressive api.
*
* Examples:
*
* var server = connect.createServer();
* server.use(connect.favicon());
* server.use(connect.logger());
* server.use(connect.static(__dirname + '/public'));
*
* If we wanted to prefix static files with _/public_, we could
* "mount" the `static()` middleware:
*
* server.use('/public', connect.static(__dirname + '/public'));
*
* This api is chainable, meaning the following is valid:
*
* connect.createServer()
* .use(connect.favicon())
* .use(connect.logger())
* .use(connect.static(__dirname + '/public'))
* .listen(3000);
*
* @param {String|Function} route or handle
* @param {Function} handle
* @return {Server}
* @api public
*/
Server.prototype.use = function(route, handle){
this.route = '/';
// default route to '/'
if ('string' != typeof route) {
handle = route;
route = '/';
}
// wrap sub-apps
if ('function' == typeof handle.handle) {
var server = handle;
server.route = route;
handle = function(req, res, next) {
server.handle(req, res, next);
};
}
// wrap vanilla http.Servers
if (handle instanceof http.Server) {
handle = handle.listeners('request')[0];
}
// normalize route to not trail with slash
if ('/' == route[route.length - 1]) {
route = route.substr(0, route.length - 1);
}
// add the middleware
this.stack.push({ route: route, handle: handle });
// allow chaining
return this;
};
/**
* Handle server requests, punting them down
* the middleware stack.
*
* @api private
*/
Server.prototype.handle = function(req, res, out) {
var writeHead = res.writeHead
, stack = this.stack
, removed = ''
, index = 0;
function next(err) {
var layer, path, c;
req.url = removed + req.url;
req.originalUrl = req.originalUrl || req.url;
removed = '';
layer = stack[index++];
// all done
if (!layer || res.headerSent) {
// but wait! we have a parent
if (out) return out(err);
// error
if (err) {
var msg = 'production' == env
? 'Internal Server Error'
: err.stack || err.toString();
// output to stderr in a non-test env
if ('test' != env) console.error(err.stack || err.toString());
// unable to respond
if (res.headerSent) return req.socket.destroy();
res.statusCode = 500;
res.setHeader('Content-Type', 'text/plain');
if ('HEAD' == req.method) return res.end();
res.end(msg);
} else {
res.statusCode = 404;
res.setHeader('Content-Type', 'text/plain');
if ('HEAD' == req.method) return res.end();
res.end('Cannot ' + req.method + ' ' + req.url);
}
return;
}
try {
path = parse(req.url).pathname;
if (undefined == path) path = '/';
// skip this layer if the route doesn't match.
if (0 != path.indexOf(layer.route)) 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 ('/' != req.url[0]) req.url = '/' + req.url;
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) {
if (e instanceof assert.AssertionError) {
console.error(e.stack + '\n');
next(e);
} else {
next(e);
}
}
}
next();
};

47
node_modules/connect/lib/https.js generated vendored Normal file
View File

@ -0,0 +1,47 @@
/*!
* Connect - HTTPServer
* Copyright(c) 2010 Sencha Inc.
* Copyright(c) 2011 TJ Holowaychuk
* MIT Licensed
*/
/**
* Module dependencies.
*/
var HTTPServer = require('./http').Server
, https = require('https');
/**
* Initialize a new `Server` with the given
*`options` and `middleware`. The HTTPS api
* is identical to the [HTTP](http.html) server,
* however TLS `options` must be provided before
* passing in the optional middleware.
*
* @params {Object} options
* @params {Array} middleawre
* @return {Server}
* @api public
*/
var Server = exports.Server = function HTTPSServer(options, middleware) {
this.stack = [];
middleware.forEach(function(fn){
this.use(fn);
}, this);
https.Server.call(this, options, this.handle);
};
/**
* Inherit from `http.Server.prototype`.
*/
Server.prototype.__proto__ = https.Server.prototype;
// mixin HTTPServer methods
Object.keys(HTTPServer.prototype).forEach(function(method){
Server.prototype[method] = HTTPServer.prototype[method];
});

46
node_modules/connect/lib/index.js generated vendored Normal file
View File

@ -0,0 +1,46 @@
/**
* # Connect
*
* Connect is a middleware framework for node,
* shipping with over 11 bundled middleware and a rich choice of
* [3rd-party middleware](https://github.com/senchalabs/connect/wiki).
*
* Installation:
*
* $ npm install connect
*
* API:
*
* - [connect](connect.html) general
* - [http](http.html) http server
* - [https](https.html) https server
*
* Middleware:
*
* - [logger](middleware-logger.html) request logger with custom format support
* - [csrf](middleware-csrf.html) Cross-site request forgery protection
* - [basicAuth](middleware-basicAuth.html) basic http authentication
* - [bodyParser](middleware-bodyParser.html) extensible request body parser
* - [cookieParser](middleware-cookieParser.html) cookie parser
* - [session](middleware-session.html) session management support with bundled [MemoryStore](middleware-session-memory.html)
* - [compiler](middleware-compiler.html) static asset compiler (sass, less, coffee-script, etc)
* - [methodOverride](middleware-methodOverride.html) faux HTTP method support
* - [responseTime](middleware-responseTime.html) calculates response-time and exposes via X-Response-Time
* - [router](middleware-router.html) provides rich Sinatra / Express-like routing
* - [staticCache](middleware-staticCache.html) memory cache layer for the static() middleware
* - [static](middleware-static.html) streaming static file server supporting `Range` and more
* - [directory](middleware-directory.html) directory listing middleware
* - [vhost](middleware-vhost.html) virtual host sub-domain mapping middleware
* - [favicon](middleware-favicon.html) efficient favicon server (with default icon)
* - [limit](middleware-limit.html) limit the bytesize of request bodies
* - [profiler](middleware-profiler.html) request profiler reporting response-time, memory usage, etc
* - [query](middleware-query.html) automatic querystring parser, populating `req.query`
* - [errorHandler](middleware-errorHandler.html) flexible error handler
*
* Internals:
*
* - connect [utilities](utils.html)
* - node monkey [patches](patch.html)
*
*/

93
node_modules/connect/lib/middleware/basicAuth.js generated vendored Normal file
View File

@ -0,0 +1,93 @@
/*!
* Connect - basicAuth
* Copyright(c) 2010 Sencha Inc.
* Copyright(c) 2011 TJ Holowaychuk
* MIT Licensed
*/
/**
* Module dependencies.
*/
var utils = require('../utils')
, unauthorized = utils.unauthorized
, badRequest = utils.badRequest;
/**
* 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.remoteUser`. The final alternative is simply passing username / password
* strings.
*
* Examples:
*
* connect(connect.basicAuth('username', 'password'));
*
* connect(
* connect.basicAuth(function(user, pass){
* return 'tj' == user & 'wahoo' == pass;
* })
* );
*
* connect(
* 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.remoteUser) return next();
if (!authorization) return unauthorized(res, realm);
var parts = authorization.split(' ')
, scheme = parts[0]
, credentials = new Buffer(parts[1], 'base64').toString().split(':');
if ('Basic' != scheme) return badRequest(res);
// async
if (callback.length >= 3) {
var pause = utils.pause(req);
callback(credentials[0], credentials[1], function(err, user){
if (err || !user) return unauthorized(res, realm);
req.remoteUser = user;
next();
pause.resume();
});
// sync
} else {
if (callback(credentials[0], credentials[1])) {
req.remoteUser = credentials[0];
next();
} else {
unauthorized(res, realm);
}
}
}
};

196
node_modules/connect/lib/middleware/bodyParser.js generated vendored Normal file
View File

@ -0,0 +1,196 @@
/*!
* Connect - bodyParser
* Copyright(c) 2010 Sencha Inc.
* Copyright(c) 2011 TJ Holowaychuk
* MIT Licensed
*/
/**
* Module dependencies.
*/
var qs = require('qs')
, formidable = require('formidable');
/**
* Extract the mime type from the given request's
* _Content-Type_ header.
*
* @param {IncomingMessage} req
* @return {String}
* @api private
*/
function mime(req) {
var str = req.headers['content-type'] || '';
return str.split(';')[0];
}
/**
* Parse request bodies.
*
* By default _application/json_, _application/x-www-form-urlencoded_,
* and _multipart/form-data_ are supported, however you may map `connect.bodyParser.parse[contentType]`
* to a function receiving `(req, options, callback)`.
*
* Examples:
*
* connect.createServer(
* connect.bodyParser()
* , function(req, res) {
* res.end('viewing user ' + req.body.user.name);
* }
* );
*
* $ curl -d 'user[name]=tj' http://localhost/
* $ curl -d '{"user":{"name":"tj"}}' -H "Content-Type: application/json" http://localhost/
*
* Multipart req.files:
*
* As a security measure files are stored in a separate object, stored
* as `req.files`. This prevents attacks that may potentially alter
* filenames, and depending on the application gain access to restricted files.
*
* Multipart configuration:
*
* The `options` passed are provided to each parser function.
* The _multipart/form-data_ parser merges these with formidable's
* IncomingForm object, allowing you to tweak the upload directory,
* size limits, etc. For example you may wish to retain the file extension
* and change the upload directory:
*
* server.use(bodyParser({ uploadDir: '/www/mysite.com/uploads' }));
*
* View [node-formidable](https://github.com/felixge/node-formidable) for more information.
*
* If you wish to use formidable directly within your app, and do not
* desire this behaviour for multipart requests simply remove the
* parser:
*
* delete connect.bodyParser.parse['multipart/form-data'];
*
* Or
*
* delete express.bodyParser.parse['multipart/form-data'];
*
* @param {Object} options
* @return {Function}
* @api public
*/
exports = module.exports = function bodyParser(options){
options = options || {};
return function bodyParser(req, res, next) {
if (req.body) return next();
req.body = {};
if ('GET' == req.method || 'HEAD' == req.method) return next();
var parser = exports.parse[mime(req)];
if (parser) {
parser(req, options, next);
} else {
next();
}
}
};
/**
* Parsers.
*/
exports.parse = {};
/**
* Parse application/x-www-form-urlencoded.
*/
exports.parse['application/x-www-form-urlencoded'] = function(req, options, fn){
var buf = '';
req.setEncoding('utf8');
req.on('data', function(chunk){ buf += chunk });
req.on('end', function(){
try {
req.body = buf.length
? qs.parse(buf)
: {};
fn();
} catch (err){
fn(err);
}
});
};
/**
* Parse application/json.
*/
exports.parse['application/json'] = function(req, options, fn){
var buf = '';
req.setEncoding('utf8');
req.on('data', function(chunk){ buf += chunk });
req.on('end', function(){
try {
req.body = buf.length
? JSON.parse(buf)
: {};
fn();
} catch (err){
fn(err);
}
});
};
/**
* Parse multipart/form-data.
*
* TODO: make multiple support optional
* TODO: revisit "error" flag if it's a formidable bug
*/
exports.parse['multipart/form-data'] = function(req, options, fn){
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){
fn(err);
done = true;
});
form.on('end', function(){
if (done) return;
try {
req.body = qs.parse(data);
req.files = qs.parse(files);
fn();
} catch (err) {
fn(err);
}
});
form.parse(req);
};

163
node_modules/connect/lib/middleware/compiler.js generated vendored Normal file
View File

@ -0,0 +1,163 @@
/*!
* Connect - compiler
* Copyright(c) 2010 Sencha Inc.
* Copyright(c) 2011 TJ Holowaychuk
* MIT Licensed
*/
/**
* Module dependencies.
*/
var fs = require('fs')
, path = require('path')
, parse = require('url').parse;
/**
* Require cache.
*/
var cache = {};
/**
* Setup compiler.
*
* Options:
*
* - `src` Source directory, defaults to **CWD**.
* - `dest` Destination directory, defaults `src`.
* - `enable` Array of enabled compilers.
*
* Compilers:
*
* - `sass` Compiles sass to css
* - `less` Compiles less to css
* - `coffeescript` Compiles coffee to js
*
* @param {Object} options
* @api public
*/
exports = module.exports = function compiler(options){
options = options || {};
var srcDir = options.src || process.cwd()
, destDir = options.dest || srcDir
, enable = options.enable;
if (!enable || enable.length === 0) {
throw new Error('compiler\'s "enable" option is not set, nothing will be compiled.');
}
return function compiler(req, res, next){
if ('GET' != req.method) return next();
var pathname = parse(req.url).pathname;
for (var i = 0, len = enable.length; i < len; ++i) {
var name = enable[i]
, compiler = compilers[name];
if (compiler.match.test(pathname)) {
var src = (srcDir + pathname).replace(compiler.match, compiler.ext)
, dest = destDir + pathname;
// Compare mtimes
fs.stat(src, function(err, srcStats){
if (err) {
if ('ENOENT' == err.code) {
next();
} else {
next(err);
}
} else {
fs.stat(dest, function(err, destStats){
if (err) {
// Oh snap! it does not exist, compile it
if ('ENOENT' == err.code) {
compile();
} else {
next(err);
}
} else {
// Source has changed, compile it
if (srcStats.mtime > destStats.mtime) {
compile();
} else {
// Defer file serving
next();
}
}
});
}
});
// Compile to the destination
function compile() {
fs.readFile(src, 'utf8', function(err, str){
if (err) {
next(err);
} else {
compiler.compile(str, function(err, str){
if (err) {
next(err);
} else {
fs.writeFile(dest, str, 'utf8', function(err){
next(err);
});
}
});
}
});
}
return;
}
}
next();
};
};
/**
* Bundled compilers:
*
* - [sass](http://github.com/visionmedia/sass.js) to _css_
* - [less](http://github.com/cloudhead/less.js) to _css_
* - [coffee](http://github.com/jashkenas/coffee-script) to _js_
*/
var compilers = exports.compilers = {
sass: {
match: /\.css$/,
ext: '.sass',
compile: function(str, fn){
var sass = cache.sass || (cache.sass = require('sass'));
try {
fn(null, sass.render(str));
} catch (err) {
fn(err);
}
}
},
less: {
match: /\.css$/,
ext: '.less',
compile: function(str, fn){
var less = cache.less || (cache.less = require('less'));
try {
less.render(str, fn);
} catch (err) {
fn(err);
}
}
},
coffeescript: {
match: /\.js$/,
ext: '.coffee',
compile: function(str, fn){
var coffee = cache.coffee || (cache.coffee = require('coffee-script'));
try {
fn(null, coffee.compile(str));
} catch (err) {
fn(err);
}
}
}
};

46
node_modules/connect/lib/middleware/cookieParser.js generated vendored Normal file
View File

@ -0,0 +1,46 @@
/*!
* Connect - cookieParser
* Copyright(c) 2010 Sencha Inc.
* Copyright(c) 2011 TJ Holowaychuk
* MIT Licensed
*/
/**
* Module dependencies.
*/
var utils = require('./../utils');
/**
* Parse _Cookie_ header and populate `req.cookies`
* with an object keyed by the cookie names.
*
* Examples:
*
* connect.createServer(
* connect.cookieParser()
* , function(req, res, next){
* res.end(JSON.stringify(req.cookies));
* }
* );
*
* @return {Function}
* @api public
*/
module.exports = function cookieParser(){
return function cookieParser(req, res, next) {
var cookie = req.headers.cookie;
if (req.cookies) return next();
req.cookies = {};
if (cookie) {
try {
req.cookies = utils.parseCookie(cookie);
} catch (err) {
return next(err);
}
}
next();
};
};

105
node_modules/connect/lib/middleware/csrf.js generated vendored Normal file
View File

@ -0,0 +1,105 @@
/*!
* Connect - csrf
* Copyright(c) 2011 Sencha Inc.
* MIT Licensed
*/
/**
* Module dependencies.
*/
var utils = require('../utils')
, crypto = require('crypto');
/**
* 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 which is re-generated per request.
*
* 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()`.
*
* Examples:
*
* var form = '\n\
* <form action="/" method="post">\n\
* <input type="hidden" name="_csrf" value="{token}" />\n\
* <input type="text" name="user[name]" value="{user}" />\n\
* <input type="password" name="user[pass]" />\n\
* <input type="submit" value="Login" />\n\
* </form>\n\
* ';
*
* connect(
* connect.cookieParser()
* , connect.session({ secret: 'keyboard cat' })
* , connect.bodyParser()
* , connect.csrf()
*
* , function(req, res, next){
* if ('POST' != req.method) return next();
* req.session.user = req.body.user;
* next();
* }
*
* , function(req, res){
* res.setHeader('Content-Type', 'text/html');
* var body = form
* .replace('{token}', req.session._csrf)
* .replace('{user}', req.session.user && req.session.user.name || '');
* res.end(body);
* }
* ).listen(3000);
*
* Options:
*
* - `value` a function accepting the request, returning the token
*
* @param {Object} options
* @api public
*/
module.exports = function csrf(options) {
var options = options || {}
, value = options.value || defaultValue;
return function(req, res, next){
// generate CSRF token
var token = req.session._csrf || (req.session._csrf = utils.uid(24));
// ignore GET (for now)
if ('GET' == req.method) return next();
// determine value
var val = value(req);
// check
if (val != token) return utils.forbidden(res);
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']);
}

222
node_modules/connect/lib/middleware/directory.js generated vendored Normal file
View File

@ -0,0 +1,222 @@
/*!
* 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 = {};
/**
* 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) {
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)
if (~path.indexOf('\0')) return utils.badRequest(res);
// malicious path
if (0 != path.indexOf(root)) return utils.forbidden(res);
// 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;
}
}
utils.notAcceptable(res);
});
});
};
};
/**
* 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'
};

100
node_modules/connect/lib/middleware/errorHandler.js generated vendored Normal file
View File

@ -0,0 +1,100 @@
/*!
* Connect - errorHandler
* Copyright(c) 2010 Sencha Inc.
* Copyright(c) 2011 TJ Holowaychuk
* MIT Licensed
*/
/**
* Module dependencies.
*/
var utils = require('../utils')
, url = require('url')
, fs = require('fs');
/**
* Flexible error handler, providing (_optional_) stack traces
* and error message responses for requests accepting text, html,
* or json.
*
* Options:
*
* - `showStack`, `stack` respond with both the error message and stack trace. Defaults to `false`
* - `showMessage`, `message`, respond with the exception message only. Defaults to `false`
* - `dumpExceptions`, `dump`, dump exceptions to stderr (without terminating the process). Defaults to `false`
*
* 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.
*
* @param {Object} options
* @return {Function}
* @api public
*/
exports = module.exports = function errorHandler(options){
options = options || {};
// defaults
var showStack = options.showStack || options.stack
, showMessage = options.showMessage || options.message
, dumpExceptions = options.dumpExceptions || options.dump
, formatUrl = options.formatUrl;
return function errorHandler(err, req, res, next){
res.statusCode = 500;
if (dumpExceptions) console.error(err.stack);
if (showStack) {
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(/\{error\}/g, utils.escape(err.toString()));
res.setHeader('Content-Type', 'text/html');
res.end(html);
});
});
// json
} else if (~accept.indexOf('json')) {
var json = JSON.stringify({ error: err });
res.setHeader('Content-Type', 'application/json');
res.end(json);
// plain text
} else {
res.writeHead(500, { 'Content-Type': 'text/plain' });
res.end(err.stack);
}
} else {
var body = showMessage
? err.toString()
: 'Internal Server Error';
res.setHeader('Content-Type', 'text/plain');
res.end(body);
}
};
};
/**
* Template title.
*/
exports.title = 'Connect';

76
node_modules/connect/lib/middleware/favicon.js generated vendored Normal file
View File

@ -0,0 +1,76 @@
/*!
* Connect - favicon
* Copyright(c) 2010 Sencha Inc.
* Copyright(c) 2011 TJ Holowaychuk
* MIT Licensed
*/
/**
* Module dependencies.
*/
var fs = require('fs')
, utils = require('../utils');
/**
* Favicon cache.
*/
var icon;
/**
* 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:
*
* connect.createServer(
* connect.favicon()
* );
*
* connect.createServer(
* connect.favicon(__dirname + '/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;
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();
}
};
};

82
node_modules/connect/lib/middleware/limit.js generated vendored Normal file
View File

@ -0,0 +1,82 @@
/*!
* Connect - limit
* Copyright(c) 2011 TJ Holowaychuk
* MIT Licensed
*/
/**
* 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.
*
* Examples:
*
* var server = connect(
* connect.limit('5.5mb')
* ).listen(3000);
*
* TODO: pause EV_READ
*
* @param {Number|String} bytes
* @return {Function}
* @api public
*/
module.exports = function limit(bytes){
if ('string' == typeof bytes) bytes = parse(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;
// deny the request
function deny() {
req.destroy();
}
// self-awareness
if (req._limit) return next();
req._limit = true;
// limit by content-length
if (len && len > bytes) {
res.statusCode = 413;
res.end('Request Entity Too Large');
return;
}
// limit
req.on('data', function(chunk){
received += chunk.length;
if (received > bytes) deny();
});
next();
};
};
/**
* Parse byte `size` string.
*
* @param {String} size
* @return {Number}
* @api private
*/
function parse(size) {
var parts = size.match(/^(\d+(?:\.\d+)?) *(kb|mb|gb)$/)
, n = parseFloat(parts[1])
, type = parts[2];
var map = {
kb: 1024
, mb: 1024 * 1024
, gb: 1024 * 1024 * 1024
};
return map[type] * n;
}

299
node_modules/connect/lib/middleware/logger.js generated vendored Normal file
View File

@ -0,0 +1,299 @@
/*!
* Connect - logger
* Copyright(c) 2010 Sencha Inc.
* Copyright(c) 2011 TJ Holowaychuk
* MIT Licensed
*/
/**
* Log buffer.
*/
var buf = [];
/**
* Default log buffer duration.
*/
var defaultBufferDuration = 1000;
/**
* 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('dev')
* connect.logger(':method :url - :referrer')
* connect.logger(':req[content-type] -> :res[content-type]')
* connect.logger(function(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(''), 'ascii');
buf.length = 0;
}
}, interval);
// swap the stream
stream = {
write: function(str){
buf.push(str);
}
};
}
return function logger(req, res, next) {
req._startTime = new Date;
// mount safety
if (req._logging) return next();
// flag as logging
req._logging = true;
// immediate
if (immediate) {
var line = fmt(exports, req, res);
if (null == line) return;
stream.write(line + '\n', 'ascii');
} else {
// proxy end to output loggging
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', 'ascii');
};
}
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
, color = 32;
if (status >= 500) color = 31
else if (status >= 400) color = 33
else if (status >= 300) color = 36;
return '\033[90m' + req.method
+ ' ' + req.originalUrl + ' '
+ '\033[' + color + 'm' + res.statusCode
+ ' \033[90m'
+ (new Date - req._startTime)
+ 'ms\033[0m';
});
// request url
exports.token('url', function(req){
return req.originalUrl;
});
// 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){
return req.socket && (req.socket.remoteAddress || (req.socket.socket && req.socket.socket.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()];
});

38
node_modules/connect/lib/middleware/methodOverride.js generated vendored Normal file
View File

@ -0,0 +1,38 @@
/*!
* Connect - methodOverride
* Copyright(c) 2010 Sencha Inc.
* Copyright(c) 2011 TJ Holowaychuk
* MIT Licensed
*/
/**
* 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();
};
};

100
node_modules/connect/lib/middleware/profiler.js generated vendored Normal file
View File

@ -0,0 +1,100 @@
/*!
* Connect - profiler
* Copyright(c) 2011 TJ Holowaychuk
* MIT Licensed
*/
/**
* Profile the duration of a request.
*
* Typically this middleware should be utilized
* _above_ all others, as it proxies the `res.end()`
* method, being first allows it to encapsulate all
* other middleware.
*
* Example Output:
*
* GET /
* response time 2ms
* memory rss 52.00kb
* memory vsize 2.07mb
* heap before 3.76mb / 8.15mb
* heap after 3.80mb / 8.15mb
*
* @api public
*/
module.exports = function profiler(){
return function(req, res, next){
var end = res.end
, start = snapshot();
// state snapshot
function snapshot() {
return {
mem: process.memoryUsage()
, time: new Date
};
}
// proxy res.end()
res.end = function(data, encoding){
res.end = end;
res.end(data, encoding);
compare(req, start, snapshot())
};
next();
}
};
/**
* Compare `start` / `end` snapshots.
*
* @param {IncomingRequest} req
* @param {Object} start
* @param {Object} end
* @api private
*/
function compare(req, start, end) {
console.log();
row(req.method, req.url);
row('response time:', (end.time - start.time) + 'ms');
row('memory rss:', formatBytes(end.mem.rss - start.mem.rss));
row('memory vsize:', formatBytes(end.mem.vsize - start.mem.vsize));
row('heap before:', formatBytes(start.mem.heapUsed) + ' / ' + formatBytes(start.mem.heapTotal));
row('heap after:', formatBytes(end.mem.heapUsed) + ' / ' + formatBytes(end.mem.heapTotal));
console.log();
}
/**
* Row helper
*
* @param {String} key
* @param {String} val
* @api private
*/
function row(key, val) {
console.log(' \033[90m%s\033[0m \033[36m%s\033[0m', key, val);
}
/**
* Format byte-size.
*
* @param {Number} bytes
* @return {String}
* @api private
*/
function formatBytes(bytes) {
var kb = 1024
, mb = 1024 * kb
, gb = 1024 * mb;
if (bytes < kb) return bytes + 'b';
if (bytes < mb) return (bytes / kb).toFixed(2) + 'kb';
if (bytes < gb) return (bytes / mb).toFixed(2) + 'mb';
return (bytes / gb).toFixed(2) + 'gb';
};

40
node_modules/connect/lib/middleware/query.js generated vendored Normal file
View File

@ -0,0 +1,40 @@
/*!
* Connect - query
* Copyright(c) 2011 TJ Holowaychuk
* Copyright(c) 2011 Sencha Inc.
* MIT Licensed
*/
/**
* Module dependencies.
*/
var qs = require('qs')
, parse = require('url').parse;
/**
* Automatically parse the query-string when available,
* populating the `req.query` object.
*
* Examples:
*
* connect(
* connect.query()
* , function(req, res){
* res.end(JSON.stringify(req.query));
* }
* ).listen(3000);
*
* @return {Function}
* @api public
*/
module.exports = function query(){
return function query(req, res, next){
req.query = ~req.url.indexOf('?')
? qs.parse(parse(req.url).query)
: {};
next();
};
};

34
node_modules/connect/lib/middleware/responseTime.js generated vendored Normal file
View File

@ -0,0 +1,34 @@
/*!
* Connect - responseTime
* Copyright(c) 2011 TJ Holowaychuk
* MIT Licensed
*/
/**
* 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 writeHead = res.writeHead
, start = new Date;
if (res._responseTime) return next();
res._responseTime = true;
// proxy writeHead to calculate duration
res.writeHead = function(status, headers){
var duration = new Date - start;
res.setHeader('X-Response-Time', duration + 'ms');
res.writeHead = writeHead;
res.writeHead(status, headers);
};
next();
};
};

379
node_modules/connect/lib/middleware/router.js generated vendored Normal file
View File

@ -0,0 +1,379 @@
/*!
* Connect - router
* Copyright(c) 2010 Sencha Inc.
* Copyright(c) 2011 TJ Holowaychuk
* MIT Licensed
*/
/**
* Module dependencies.
*/
var utils = require('../utils')
, parse = require('url').parse;
/**
* Expose router.
*/
exports = module.exports = router;
/**
* Supported HTTP / WebDAV methods.
*/
var _methods = exports.methods = [
'get'
, 'post'
, 'put'
, 'delete'
, 'connect'
, 'options'
, 'trace'
, 'copy'
, 'lock'
, 'mkcol'
, 'move'
, 'propfind'
, 'proppatch'
, 'unlock'
, 'report'
, 'mkactivity'
, 'checkout'
, 'merge'
];
/**
* Provides Sinatra and Express-like routing capabilities.
*
* Examples:
*
* connect.router(function(app){
* app.get('/user/:id', function(req, res, next){
* // populates req.params.id
* });
* app.put('/user/:id', function(req, res, next){
* // populates req.params.id
* });
* })
*
* @param {Function} fn
* @return {Function}
* @api public
*/
function router(fn){
var self = this
, methods = {}
, routes = {}
, params = {};
if (!fn) throw new Error('router provider requires a callback function');
// Generate method functions
_methods.forEach(function(method){
methods[method] = generateMethodFunction(method.toUpperCase());
});
// Alias del -> delete
methods.del = methods.delete;
// Apply callback to all methods
methods.all = function(){
var args = arguments;
_methods.forEach(function(name){
methods[name].apply(this, args);
});
return self;
};
// Register param callback
methods.param = function(name, fn){
params[name] = fn;
};
fn.call(this, methods);
function generateMethodFunction(name) {
var localRoutes = routes[name] = routes[name] || [];
return function(path, fn){
var keys = []
, middleware = [];
// slice middleware
if (arguments.length > 2) {
middleware = Array.prototype.slice.call(arguments, 1, arguments.length);
fn = middleware.pop();
middleware = utils.flatten(middleware);
}
fn.middleware = middleware;
if (!path) throw new Error(name + ' route requires a path');
if (!fn) throw new Error(name + ' route ' + path + ' requires a callback');
var regexp = path instanceof RegExp
? path
: normalizePath(path, keys);
localRoutes.push({
fn: fn
, path: regexp
, keys: keys
, orig: path
, method: name
});
return self;
};
}
function router(req, res, next){
var route
, self = this;
(function pass(i){
if (route = match(req, routes, i)) {
var i = 0
, keys = route.keys;
req.params = route.params;
// Param preconditions
(function param(err) {
try {
var key = keys[i++]
, val = req.params[key]
, fn = params[key];
if ('route' == err) {
pass(req._route_index + 1);
// Error
} else if (err) {
next(err);
// Param has callback
} else if (fn) {
// Return style
if (1 == fn.length) {
req.params[key] = fn(val);
param();
// Middleware style
} else {
fn(req, res, param, val);
}
// Finished processing params
} else if (!key) {
// route middleware
i = 0;
(function nextMiddleware(err){
var fn = route.middleware[i++];
if ('route' == err) {
pass(req._route_index + 1);
} else if (err) {
next(err);
} else if (fn) {
fn(req, res, nextMiddleware);
} else {
route.call(self, req, res, function(err){
if (err) {
next(err);
} else {
pass(req._route_index + 1);
}
});
}
})();
// More params
} else {
param();
}
} catch (err) {
next(err);
}
})();
} else if ('OPTIONS' == req.method) {
options(req, res, routes);
} else {
next();
}
})();
};
router.remove = function(path, method){
var fns = router.lookup(path, method);
fns.forEach(function(fn){
routes[fn.method].splice(fn.index, 1);
});
};
router.lookup = function(path, method, ret){
ret = ret || [];
// method specific lookup
if (method) {
method = method.toUpperCase();
if (routes[method]) {
routes[method].forEach(function(route, i){
if (path == route.orig) {
var fn = route.fn;
fn.regexp = route.path;
fn.keys = route.keys;
fn.path = route.orig;
fn.method = route.method;
fn.index = i;
ret.push(fn);
}
});
}
// global lookup
} else {
_methods.forEach(function(method){
router.lookup(path, method, ret);
});
}
return ret;
};
router.match = function(url, method, ret){
var ret = ret || []
, i = 0
, fn
, req;
// method specific matches
if (method) {
method = method.toUpperCase();
req = { url: url, method: method };
while (fn = match(req, routes, i)) {
i = req._route_index + 1;
ret.push(fn);
}
// global matches
} else {
_methods.forEach(function(method){
router.match(url, method, ret);
});
}
return ret;
};
return router;
}
/**
* Respond to OPTIONS.
*
* @param {ServerRequest} req
* @param {ServerResponse} req
* @param {Array} routes
* @api private
*/
function options(req, res, routes) {
var pathname = parse(req.url).pathname
, body = optionsFor(pathname, routes).join(',');
res.writeHead(200, {
'Content-Length': body.length
, 'Allow': body
});
res.end(body);
}
/**
* Return OPTIONS array for the given `path`, matching `routes`.
*
* @param {String} path
* @param {Array} routes
* @return {Array}
* @api private
*/
function optionsFor(path, routes) {
return _methods.filter(function(method){
var arr = routes[method.toUpperCase()];
for (var i = 0, len = arr.length; i < len; ++i) {
if (arr[i].path.test(path)) return true;
}
}).map(function(method){
return method.toUpperCase();
});
}
/**
* Normalize the given path string,
* returning a regular expression.
*
* An empty array should be passed,
* which will contain the placeholder
* key names. For example "/user/:id" will
* then contain ["id"].
*
* @param {String} path
* @param {Array} keys
* @return {RegExp}
* @api private
*/
function normalizePath(path, keys) {
path = path
.concat('/?')
.replace(/\/\(/g, '(?:/')
.replace(/(\/)?(\.)?:(\w+)(?:(\(.*?\)))?(\?)?/g, function(_, slash, format, key, capture, optional){
keys.push(key);
slash = slash || '';
return ''
+ (optional ? '' : slash)
+ '(?:'
+ (optional ? slash : '')
+ (format || '') + (capture || '([^/]+?)') + ')'
+ (optional || '');
})
.replace(/([\/.])/g, '\\$1')
.replace(/\*/g, '(.+)');
return new RegExp('^' + path + '$', 'i');
}
/**
* Attempt to match the given request to
* one of the routes. When successful
* a route function is returned.
*
* @param {ServerRequest} req
* @param {Object} routes
* @return {Function}
* @api private
*/
function match(req, routes, i) {
var captures
, method = req.method
, i = i || 0;
if ('HEAD' == method) method = 'GET';
if (routes = routes[method]) {
var url = parse(req.url)
, pathname = url.pathname;
for (var len = routes.length; i < len; ++i) {
var route = routes[i]
, fn = route.fn
, path = route.path
, keys = fn.keys = route.keys;
if (captures = path.exec(pathname)) {
fn.method = method;
fn.params = [];
for (var j = 1, len = captures.length; j < len; ++j) {
var key = keys[j-1],
val = typeof captures[j] === 'string'
? decodeURIComponent(captures[j])
: captures[j];
if (key) {
fn.params[key] = val;
} else {
fn.params.push(val);
}
}
req._route_index = i;
return fn;
}
}
}
}

346
node_modules/connect/lib/middleware/session.js generated vendored Normal file
View File

@ -0,0 +1,346 @@
/*!
* Connect - session
* Copyright(c) 2010 Sencha Inc.
* Copyright(c) 2011 TJ Holowaychuk
* MIT Licensed
*/
/**
* Module dependencies.
*/
var Session = require('./session/session')
, MemoryStore = require('./session/memory')
, Cookie = require('./session/cookie')
, Store = require('./session/store')
, utils = require('./../utils')
, parse = require('url').parse
, crypto = require('crypto');
// 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 obviously only work within a single process.';
/**
* Default finger-printing function.
*/
function defaultFingerprint(req) {
var ua = req.headers['user-agent'] || '';
return ua.replace(/;?\schromeframe\/[\d\.]+/, '');
};
/**
* Paths to ignore.
*/
exports.ignore = [];
/**
* 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()](middleware-cookieParser.html)
* middleware _before_ `session()`.
*
* Examples:
*
* connect.createServer(
* connect.cookieParser()
* , connect.session({ secret: 'keyboard cat' })
* );
*
* Options:
*
* - `key` cookie name defaulting to `connect.sid`
* - `store` Session store instance
* - `fingerprint` Custom fingerprint generating function
* - `cookie` Session cookie settings, defaulting to `{ path: '/', httpOnly: true, maxAge: 14400000 }`
* - `secret` Secret string used to compute hash
*
* Ignore Paths:
*
* By default `/favicon.ico` is the only ignored path, all others
* will utilize sessions, to manipulate the paths ignored, use
* `connect.session.ignore.push('/my/path')`. This works for _full_
* pathnames only, not segments nor substrings.
*
* connect.session.ignore.push('/robots.txt');
*
* ## 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(
* connect.cookieParser()
* , connect.session({ secret: 'keyboard cat', cookie: { maxAge: 60000 }})
* , connect.favicon()
* , 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`, and `.lastAccess` properties. 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 update `req.session.lastAccess`,
* and 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'
, secret = options.secret
, store = options.store || new MemoryStore
, fingerprint = options.fingerprint || defaultFingerprint
, cookie = options.cookie;
// notify user that this store is not
// meant for a production environment
if ('production' == env && store instanceof MemoryStore) {
console.warn(warning);
}
// ensure secret is present
if (!secret) {
throw new Error('connect.session({ secret: "string" }) required for security');
}
// session hashing function
store.hash = function(req, base) {
return crypto
.createHmac('sha256', secret)
.update(base + fingerprint(req))
.digest('base64')
.replace(/=*$/, '');
};
// generates the new session
store.generate = function(req){
var base = utils.uid(24);
var sessionID = base + '.' + store.hash(req, base);
req.sessionID = sessionID;
req.session = new Session(req);
req.session.cookie = new Cookie(cookie);
};
return function session(req, res, next) {
// self-awareness
if (req.session) return next();
// parse url
var url = parse(req.url)
, path = url.pathname;
// ignorable paths
if (~exports.ignore.indexOf(path)) return next();
// expose store
req.sessionStore = store;
// proxy writeHead() to Set-Cookie
var writeHead = res.writeHead;
res.writeHead = function(status, headers){
if (req.session) {
var cookie = req.session.cookie;
// only send secure session cookies when there is a secure connection.
// proxySecure is a custom attribute to allow for a reverse proxy
// to handle SSL connections and to communicate to connect over HTTP that
// the incoming connection is secure.
var secured = cookie.secure && (req.connection.encrypted || req.connection.proxySecure);
if (secured || !cookie.secure) {
res.setHeader('Set-Cookie', cookie.serialize(key, req.sessionID));
}
}
res.writeHead = writeHead;
return res.writeHead(status, headers);
};
// proxy end() to commit the session
var end = res.end;
res.end = function(data, encoding){
res.end = end;
if (req.session) {
// HACK: ensure Set-Cookie for implicit writeHead()
if (!res._header) res._implicitHeader();
req.session.resetMaxAge();
req.session.save(function(){
res.end(data, encoding);
});
} else {
res.end(data, encoding);
}
};
// session hashing
function hash(base) {
return store.hash(req, base);
}
// generate the session
function generate() {
store.generate(req);
}
// get the sessionID from the cookie
req.sessionID = req.cookies[key];
// make a new session if the browser doesn't send a sessionID
if (!req.sessionID) {
generate();
next();
return;
}
// check the fingerprint
var parts = req.sessionID.split('.');
if (parts[1] != hash(parts[0])) {
generate();
next();
return;
}
// generate the session object
var pause = utils.pause(req);
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) {
if ('ENOENT' == err.code) {
generate();
next();
} else {
next(err);
}
// no session
} else if (!sess) {
generate();
next();
// populate req.session
} else {
store.createSession(req, sess);
next();
}
});
};
};

126
node_modules/connect/lib/middleware/session/cookie.js generated vendored Normal file
View File

@ -0,0 +1,126 @@
/*!
* Connect - session - Cookie
* Copyright(c) 2010 Sencha Inc.
* Copyright(c) 2011 TJ Holowaychuk
* MIT Licensed
*/
/**
* Module dependencies.
*/
var utils = require('../../utils');
/**
* Initialize a new `Cookie` with the given `options`.
*
* @param {Object} options
* @api private
*/
var Cookie = module.exports = function Cookie(options) {
this.path = '/';
this.httpOnly = true;
this.maxAge = 14400000;
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
}
},
/**
* Return a serialized cookie string.
*
* @return {String}
* @api public
*/
serialize: function(name, val){
return utils.serializeCookie(name, val, this.data);
},
/**
* Return JSON representation of this cookie.
*
* @return {Object}
* @api private
*/
toJSON: function(){
return this.data;
}
};

131
node_modules/connect/lib/middleware/session/memory.js generated vendored Normal file
View File

@ -0,0 +1,131 @@
/*!
* Connect - session - MemoryStore
* Copyright(c) 2010 Sencha Inc.
* Copyright(c) 2011 TJ Holowaychuk
* MIT Licensed
*/
/**
* Module dependencies.
*/
var Store = require('./store')
, utils = require('../../utils')
, Session = require('./session');
/**
* 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);
};

137
node_modules/connect/lib/middleware/session/session.js generated vendored Normal file
View File

@ -0,0 +1,137 @@
/*!
* Connect - session - Session
* Copyright(c) 2010 Sencha Inc.
* Copyright(c) 2011 TJ Holowaychuk
* MIT Licensed
*/
/**
* Module dependencies.
*/
var utils = require('../../utils')
, Cookie = require('./cookie');
/**
* 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);
} else {
this.lastAccess = Date.now();
}
};
/**
* Update `.lastAccess` timestamp,
* and 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
.resetLastAccess()
.resetMaxAge();
};
/**
* Update `.lastAccess` timestamp.
*
* @return {Session} for chaining
* @api public
*/
Session.prototype.resetLastAccess = function(){
this.lastAccess = Date.now();
return this;
};
/**
* 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 or lastAccess 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;
};

87
node_modules/connect/lib/middleware/session/store.js generated vendored Normal file
View File

@ -0,0 +1,87 @@
/*!
* 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')
, utils = require('../../utils');
/**
* 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, false);
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, update){
var expires = sess.cookie.expires
, orig = sess.cookie.originalMaxAge
, update = null == update ? true : false;
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);
if (update) req.session.resetLastAccess();
return req.session;
};

225
node_modules/connect/lib/middleware/static.js generated vendored Normal file
View File

@ -0,0 +1,225 @@
/*!
* Connect - staticProvider
* Copyright(c) 2010 Sencha Inc.
* Copyright(c) 2011 TJ Holowaychuk
* MIT Licensed
*/
/**
* Module dependencies.
*/
var fs = require('fs')
, path = require('path')
, join = path.join
, basename = path.basename
, normalize = path.normalize
, utils = require('../utils')
, Buffer = require('buffer').Buffer
, parse = require('url').parse
, mime = require('mime');
/**
* Static file server with the given `root` path.
*
* Examples:
*
* var oneDay = 86400000;
*
* connect(
* connect.static(__dirname + '/public')
* ).listen(3000);
*
* connect(
* connect.static(__dirname + '/public', { maxAge: oneDay })
* ).listen(3000);
*
* 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
*
* @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');
options.root = root;
return function static(req, res, next) {
options.path = req.url;
options.getOnly = true;
send(req, res, next, options);
};
};
/**
* Expose mime module.
*/
exports.mime = mime;
/**
* Respond with 416 "Requested Range Not Satisfiable"
*
* @param {ServerResponse} res
* @api private
*/
function invalidRange(res) {
var body = 'Requested Range Not Satisfiable';
res.setHeader('Content-Type', 'text/plain');
res.setHeader('Content-Length', body.length);
res.statusCode = 416;
res.end(body);
}
/**
* Attempt to tranfer the requseted file to `res`.
*
* @param {ServerRequest}
* @param {ServerResponse}
* @param {Function} next
* @param {Object} options
* @api private
*/
var send = exports.send = function(req, res, next, options){
options = options || {};
if (!options.path) throw new Error('path required');
// setup
var maxAge = options.maxAge || 0
, ranges = req.headers.range
, head = 'HEAD' == req.method
, get = 'GET' == req.method
, root = options.root ? normalize(options.root) : null
, redirect = false === options.redirect ? false : true
, getOnly = options.getOnly
, fn = options.callback
, hidden = options.hidden
, done;
// replace next() with callback when available
if (fn) next = fn;
// ignore non-GET requests
if (getOnly && !get && !head) return next();
// parse url
var url = parse(options.path)
, path = decodeURIComponent(url.pathname)
, type;
// null byte(s)
if (~path.indexOf('\0')) return utils.badRequest(res);
// when root is not given, consider .. malicious
if (!root && ~path.indexOf('..')) return utils.forbidden(res);
// join / normalize from optional root dir
path = normalize(join(root, path));
// malicious path
if (root && 0 != path.indexOf(root)) return fn
? fn(new Error('Forbidden'))
: utils.forbidden(res);
// index.html support
if (normalize('/') == path[path.length - 1]) path += 'index.html';
// "hidden" file
if (!hidden && '.' == basename(path)[0]) return next();
fs.stat(path, function(err, stat){
// mime type
type = mime.lookup(path);
// ignore ENOENT
if (err) {
if (fn) return fn(err);
return 'ENOENT' == err.code
? next()
: next(err);
// redirect directory in case index.html is present
} else if (stat.isDirectory()) {
if (!redirect) return next();
res.statusCode = 301;
res.setHeader('Location', url.pathname + '/');
res.end('Redirecting to ' + url.pathname + '/');
return;
}
// header fields
if (!res.getHeader('Date')) res.setHeader('Date', new Date().toUTCString());
if (!res.getHeader('Cache-Control')) res.setHeader('Cache-Control', 'public, max-age=' + (maxAge / 1000));
if (!res.getHeader('Last-Modified')) res.setHeader('Last-Modified', stat.mtime.toUTCString());
if (!res.getHeader('ETag')) res.setHeader('ETag', utils.etag(stat));
if (!res.getHeader('content-type')) {
var charset = mime.charsets.lookup(type);
res.setHeader('Content-Type', type + (charset ? '; charset=' + charset : ''));
}
res.setHeader('Accept-Ranges', 'bytes');
// conditional GET support
if (utils.conditionalGET(req)) {
if (!utils.modified(req, res)) {
req.emit('static');
return utils.notModified(res);
}
}
var opts = {};
var chunkSize = stat.size;
// we have a Range request
if (ranges) {
ranges = utils.parseRange(stat.size, ranges);
// valid
if (ranges) {
// TODO: stream options
// TODO: multiple support
opts.start = ranges[0].start;
opts.end = ranges[0].end;
chunkSize = opts.end - opts.start + 1;
res.statusCode = 206;
res.setHeader('Content-Range', 'bytes '
+ opts.start
+ '-'
+ opts.end
+ '/'
+ stat.size);
// invalid
} else {
return fn
? fn(new Error('Requested Range Not Satisfiable'))
: invalidRange(res);
}
}
res.setHeader('Content-Length', chunkSize);
// transfer
if (head) return res.end();
// stream
var stream = fs.createReadStream(path, opts);
req.emit('static', stream);
stream.pipe(res);
// callback
if (fn) {
function callback(err) { done || fn(err); done = true }
req.on('close', callback);
stream.on('end', callback);
}
});
};

175
node_modules/connect/lib/middleware/staticCache.js generated vendored Normal file
View File

@ -0,0 +1,175 @@
/*!
* Connect - staticCache
* Copyright(c) 2011 Sencha Inc.
* MIT Licensed
*/
/**
* Module dependencies.
*/
var http = require('http')
, utils = require('../utils')
, Cache = require('../cache')
, url = require('url')
, fs = require('fs');
/**
* 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 {Type} name
* @return {Type}
* @api public
*/
module.exports = function staticCache(options){
var options = options || {}
, cache = new Cache(options.maxObjects || 128)
, maxlen = options.maxLength || 1024 * 256;
return function staticCache(req, res, next){
var path = url.parse(req.url).pathname
, ranges = req.headers.range
, hit = cache.get(path)
, hitCC
, uaCC
, header
, age;
// cache static
req.on('static', function(stream){
var headers = res._headers
, cc = utils.parseCacheControl(headers['cache-control'] || '')
, contentLength = headers['content-length']
, hit;
// ignore larger files
if (!contentLength || contentLength > maxlen) return;
// dont cache items we shouldn't be
if ( cc['no-cache']
|| cc['no-store']
|| cc['private']
|| cc['must-revalidate']) return;
// if already in cache then validate
if (hit = cache.get(path)){
if (headers.etag == hit[0].etag) {
hit[0].date = new Date;
return;
} else {
cache.remove(path);
}
}
// validation notifiactions don't contain a steam
if (null == stream) return;
// add the cache object
var arr = cache.add(path);
arr.push(headers);
// store the chunks
stream.on('data', function(chunk){
arr.push(chunk);
});
// flag it as complete
stream.on('end', function(){
arr.complete = true;
});
});
// cache hit, doesnt support range requests
if (hit && hit.complete && !ranges) {
header = utils.merge({}, hit[0]);
header.Age = age = (new Date - new Date(header.date)) / 1000 | 0;
header.date = new Date().toUTCString();
// parse cache-controls
hitCC = utils.parseCacheControl(header['cache-control'] || '');
uaCC = utils.parseCacheControl(req.headers['cache-control'] || '');
// check if we must revalidate(bypass)
if (hitCC['no-cache'] || uaCC['no-cache']) return next();
// check freshness of entity
if (isStale(hitCC, age) || isStale(uaCC, age)) return next();
// conditional GET support
if (utils.conditionalGET(req)) {
if (!utils.modified(req, res, header)) {
header['content-length'] = 0;
res.writeHead(304, header);
return res.end();
}
}
// HEAD support
if ('HEAD' == req.method) {
header['content-length'] = 0;
res.writeHead(200, header);
return res.end();
}
// respond with cache
res.writeHead(200, header);
// backpressure
function write(i) {
var buf = hit[i];
if (!buf) return res.end();
if (false === res.write(buf)) {
res.once('drain', function(){
write(++i);
});
} else {
write(++i);
}
}
return write(1);
}
next();
}
};
/**
* Check if cache item is stale
*
* @param {Object} cc
* @param {Number} age
* @return {Boolean}
* @api private
*/
function isStale(cc, age) {
return cc['max-age'] && cc['max-age'] <= age;
}

44
node_modules/connect/lib/middleware/vhost.js generated vendored Normal file
View File

@ -0,0 +1,44 @@
/*!
* Connect - vhost
* Copyright(c) 2010 Sencha Inc.
* Copyright(c) 2011 TJ Holowaychuk
* MIT Licensed
*/
/**
* Setup vhost for the given `hostname` and `server`.
*
* Examples:
*
* connect(
* connect.vhost('foo.com',
* connect.createServer(...middleware...)
* ),
* connect.vhost('bar.com',
* connect.createServer(...middleware...)
* )
* );
*
* @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(/[*]/g, '(.*?)') + '$');
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 (req.subdomains = regexp.exec(host)) {
req.subdomains = req.subdomains[0].split('.').slice(0, -1);
server.emit("request", req, res);
} else {
next();
}
};
};

79
node_modules/connect/lib/patch.js generated vendored Normal file
View File

@ -0,0 +1,79 @@
/*!
* Connect
* Copyright(c) 2011 TJ Holowaychuk
* MIT Licensed
*/
/**
* Module dependencies.
*/
var http = require('http')
, res = http.OutgoingMessage.prototype;
// original setHeader()
var setHeader = res.setHeader;
// original _renderHeaders()
var _renderHeaders = res._renderHeaders;
if (res._hasConnectPatch) return;
/**
* Provide a public "header sent" flag
* until node does.
*
* @return {Boolean}
* @api public
*/
res.__defineGetter__('headerSent', function(){
return this._headerSent;
});
/**
* 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 `res.end()` to expose a 'header' event,
* allowing arbitrary augmentation before the header
* fields are written to the socket.
*
* NOTE: this _only_ supports node's progressive header
* field API aka `res.setHeader()`.
*/
res._renderHeaders = function(){
this.emit('header');
return _renderHeaders.call(this);
};
res._hasConnectPatch = true;

75
node_modules/connect/lib/public/directory.html generated vendored Normal file
View File

@ -0,0 +1,75 @@
<html>
<head>
<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 = 'DOMContentLoaded';
el.addEventListener(event, fn, false);
};
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>

13
node_modules/connect/lib/public/error.html generated vendored Normal file
View File

@ -0,0 +1,13 @@
<html>
<head>
<title>{error}</title>
<style>{style}</style>
</head>
<body>
<div id="wrapper">
<h1>{title}</h1>
<h2><em>500</em> {error}</h2>
<ul id="stacktrace">{stack}</ul>
</div>
</body>
</html>

BIN
node_modules/connect/lib/public/favicon.ico generated vendored Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 KiB

BIN
node_modules/connect/lib/public/icons/page.png generated vendored Executable file

Binary file not shown.

After

Width:  |  Height:  |  Size: 635 B

BIN
node_modules/connect/lib/public/icons/page_add.png generated vendored Executable file

Binary file not shown.

After

Width:  |  Height:  |  Size: 739 B

BIN
node_modules/connect/lib/public/icons/page_attach.png generated vendored Executable file

Binary file not shown.

After

Width:  |  Height:  |  Size: 794 B

BIN
node_modules/connect/lib/public/icons/page_code.png generated vendored Executable file

Binary file not shown.

After

Width:  |  Height:  |  Size: 818 B

BIN
node_modules/connect/lib/public/icons/page_copy.png generated vendored Executable file

Binary file not shown.

After

Width:  |  Height:  |  Size: 663 B

BIN
node_modules/connect/lib/public/icons/page_delete.png generated vendored Executable file

Binary file not shown.

After

Width:  |  Height:  |  Size: 740 B

BIN
node_modules/connect/lib/public/icons/page_edit.png generated vendored Executable file

Binary file not shown.

After

Width:  |  Height:  |  Size: 807 B

BIN
node_modules/connect/lib/public/icons/page_error.png generated vendored Executable file

Binary file not shown.

After

Width:  |  Height:  |  Size: 793 B

BIN
node_modules/connect/lib/public/icons/page_excel.png generated vendored Executable file

Binary file not shown.

After

Width:  |  Height:  |  Size: 817 B

BIN
node_modules/connect/lib/public/icons/page_find.png generated vendored Executable file

Binary file not shown.

After

Width:  |  Height:  |  Size: 879 B

BIN
node_modules/connect/lib/public/icons/page_gear.png generated vendored Executable file

Binary file not shown.

After

Width:  |  Height:  |  Size: 833 B

BIN
node_modules/connect/lib/public/icons/page_go.png generated vendored Executable file

Binary file not shown.

After

Width:  |  Height:  |  Size: 779 B

BIN
node_modules/connect/lib/public/icons/page_green.png generated vendored Executable file

Binary file not shown.

After

Width:  |  Height:  |  Size: 621 B

BIN
node_modules/connect/lib/public/icons/page_key.png generated vendored Executable file

Binary file not shown.

After

Width:  |  Height:  |  Size: 801 B

BIN
node_modules/connect/lib/public/icons/page_lightning.png generated vendored Executable file

Binary file not shown.

After

Width:  |  Height:  |  Size: 839 B

BIN
node_modules/connect/lib/public/icons/page_link.png generated vendored Executable file

Binary file not shown.

After

Width:  |  Height:  |  Size: 830 B

BIN
node_modules/connect/lib/public/icons/page_paintbrush.png generated vendored Executable file

Binary file not shown.

After

Width:  |  Height:  |  Size: 813 B

BIN
node_modules/connect/lib/public/icons/page_paste.png generated vendored Executable file

Binary file not shown.

After

Width:  |  Height:  |  Size: 703 B

BIN
node_modules/connect/lib/public/icons/page_red.png generated vendored Executable file

Binary file not shown.

After

Width:  |  Height:  |  Size: 641 B

BIN
node_modules/connect/lib/public/icons/page_refresh.png generated vendored Executable file

Binary file not shown.

After

Width:  |  Height:  |  Size: 858 B

BIN
node_modules/connect/lib/public/icons/page_save.png generated vendored Executable file

Binary file not shown.

After

Width:  |  Height:  |  Size: 774 B

BIN
node_modules/connect/lib/public/icons/page_white.png generated vendored Executable file

Binary file not shown.

After

Width:  |  Height:  |  Size: 294 B

BIN
node_modules/connect/lib/public/icons/page_white_acrobat.png generated vendored Executable file

Binary file not shown.

After

Width:  |  Height:  |  Size: 591 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 664 B

BIN
node_modules/connect/lib/public/icons/page_white_add.png generated vendored Executable file

Binary file not shown.

After

Width:  |  Height:  |  Size: 512 B

BIN
node_modules/connect/lib/public/icons/page_white_c.png generated vendored Executable file

Binary file not shown.

After

Width:  |  Height:  |  Size: 587 B

BIN
node_modules/connect/lib/public/icons/page_white_camera.png generated vendored Executable file

Binary file not shown.

After

Width:  |  Height:  |  Size: 656 B

BIN
node_modules/connect/lib/public/icons/page_white_cd.png generated vendored Executable file

Binary file not shown.

After

Width:  |  Height:  |  Size: 666 B

BIN
node_modules/connect/lib/public/icons/page_white_code.png generated vendored Executable file

Binary file not shown.

After

Width:  |  Height:  |  Size: 603 B

BIN
node_modules/connect/lib/public/icons/page_white_code_red.png generated vendored Executable file

Binary file not shown.

After

Width:  |  Height:  |  Size: 587 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 592 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 724 B

BIN
node_modules/connect/lib/public/icons/page_white_copy.png generated vendored Executable file

Binary file not shown.

After

Width:  |  Height:  |  Size: 309 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 621 B

BIN
node_modules/connect/lib/public/icons/page_white_csharp.png generated vendored Executable file

Binary file not shown.

After

Width:  |  Height:  |  Size: 700 B

BIN
node_modules/connect/lib/public/icons/page_white_cup.png generated vendored Executable file

Binary file not shown.

After

Width:  |  Height:  |  Size: 639 B

BIN
node_modules/connect/lib/public/icons/page_white_database.png generated vendored Executable file

Binary file not shown.

After

Width:  |  Height:  |  Size: 579 B

BIN
node_modules/connect/lib/public/icons/page_white_delete.png generated vendored Executable file

Binary file not shown.

After

Width:  |  Height:  |  Size: 536 B

BIN
node_modules/connect/lib/public/icons/page_white_dvd.png generated vendored Executable file

Binary file not shown.

After

Width:  |  Height:  |  Size: 638 B

BIN
node_modules/connect/lib/public/icons/page_white_edit.png generated vendored Executable file

Binary file not shown.

After

Width:  |  Height:  |  Size: 618 B

BIN
node_modules/connect/lib/public/icons/page_white_error.png generated vendored Executable file

Binary file not shown.

After

Width:  |  Height:  |  Size: 623 B

BIN
node_modules/connect/lib/public/icons/page_white_excel.png generated vendored Executable file

Binary file not shown.

After

Width:  |  Height:  |  Size: 663 B

BIN
node_modules/connect/lib/public/icons/page_white_find.png generated vendored Executable file

Binary file not shown.

After

Width:  |  Height:  |  Size: 676 B

BIN
node_modules/connect/lib/public/icons/page_white_flash.png generated vendored Executable file

Binary file not shown.

After

Width:  |  Height:  |  Size: 582 B

BIN
node_modules/connect/lib/public/icons/page_white_freehand.png generated vendored Executable file

Binary file not shown.

After

Width:  |  Height:  |  Size: 639 B

BIN
node_modules/connect/lib/public/icons/page_white_gear.png generated vendored Executable file

Binary file not shown.

After

Width:  |  Height:  |  Size: 402 B

BIN
node_modules/connect/lib/public/icons/page_white_get.png generated vendored Executable file

Binary file not shown.

After

Width:  |  Height:  |  Size: 516 B

BIN
node_modules/connect/lib/public/icons/page_white_go.png generated vendored Executable file

Binary file not shown.

After

Width:  |  Height:  |  Size: 612 B

BIN
node_modules/connect/lib/public/icons/page_white_h.png generated vendored Executable file

Binary file not shown.

After

Width:  |  Height:  |  Size: 603 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 296 B

BIN
node_modules/connect/lib/public/icons/page_white_key.png generated vendored Executable file

Binary file not shown.

After

Width:  |  Height:  |  Size: 616 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 669 B

BIN
node_modules/connect/lib/public/icons/page_white_link.png generated vendored Executable file

Binary file not shown.

After

Width:  |  Height:  |  Size: 614 B

BIN
node_modules/connect/lib/public/icons/page_white_magnify.png generated vendored Executable file

Binary file not shown.

After

Width:  |  Height:  |  Size: 554 B

BIN
node_modules/connect/lib/public/icons/page_white_medal.png generated vendored Executable file

Binary file not shown.

After

Width:  |  Height:  |  Size: 706 B

BIN
node_modules/connect/lib/public/icons/page_white_office.png generated vendored Executable file

Binary file not shown.

After

Width:  |  Height:  |  Size: 779 B

BIN
node_modules/connect/lib/public/icons/page_white_paint.png generated vendored Executable file

Binary file not shown.

After

Width:  |  Height:  |  Size: 688 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 618 B

BIN
node_modules/connect/lib/public/icons/page_white_paste.png generated vendored Executable file

Binary file not shown.

After

Width:  |  Height:  |  Size: 620 B

BIN
node_modules/connect/lib/public/icons/page_white_php.png generated vendored Executable file

Binary file not shown.

After

Width:  |  Height:  |  Size: 538 B

Some files were not shown because too many files have changed in this diff Show More