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

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();
}
};
};