Commit 5dab766b authored by Leo Iannacone's avatar Leo Iannacone

update to express 3.5

parent 2a5c90be
...@@ -13,6 +13,11 @@ ...@@ -13,6 +13,11 @@
- `req.accepts*` with [accepts](https://github.com/expressjs/accepts) - `req.accepts*` with [accepts](https://github.com/expressjs/accepts)
- `req.is` with [type-is](https://github.com/expressjs/type-is) - `req.is` with [type-is](https://github.com/expressjs/type-is)
3.5.0 / 2014-03-06
==================
* bump deps
3.4.8 / 2014-01-13 3.4.8 / 2014-01-13
================== ==================
......
...@@ -357,7 +357,7 @@ function createApplicationAt(path) { ...@@ -357,7 +357,7 @@ function createApplicationAt(path) {
// CSS Engine support // CSS Engine support
switch (program.css) { switch (program.css) {
case 'less': case 'less':
pkg.dependencies['less-middleware'] = '*'; pkg.dependencies['less-middleware'] = '~0.1.15';
break; break;
default: default:
if (program.css) { if (program.css) {
......
...@@ -3,7 +3,7 @@ ...@@ -3,7 +3,7 @@
Connect is an extensible HTTP server framework for [node](http://nodejs.org), providing high performance "plugins" known as _middleware_. Connect is an extensible HTTP server framework for [node](http://nodejs.org), providing high performance "plugins" known as _middleware_.
Connect is bundled with over _20_ commonly used middleware, including Connect is bundled with over _20_ commonly used middleware, including
a logger, session support, cookie parser, and [more](http://senchalabs.github.com/connect). Be sure to view the 2.x [documentation](http://senchalabs.github.com/connect/). a logger, session support, cookie parser, and [more](http://senchalabs.github.com/connect). Be sure to view the 2.x [documentation](http://www.senchalabs.org/connect/).
```js ```js
var connect = require('connect') var connect = require('connect')
......
...@@ -19,28 +19,28 @@ ...@@ -19,28 +19,28 @@
* *
* Middleware: * Middleware:
* *
* - [logger](logger.html) request logger with custom format support * - [basicAuth](https://github.com/expressjs/basic-auth-connect) basic http authentication
* - [csrf](csrf.html) Cross-site request forgery protection * - [cookieParser](https://github.com/expressjs/cookie-parser) cookie parser
* - [compress](compress.html) Gzip compression middleware * - [compress](https://github.com/expressjs/compression) Gzip compression middleware
* - [basicAuth](basicAuth.html) basic http authentication * - [csrf](https://github.com/expressjs/csurf) Cross-site request forgery protection
* - [directory](https://github.com/expressjs/serve-index) directory listing middleware
* - [errorHandler](https://github.com/expressjs/errorhandler) flexible error handler
* - [favicon](https://github.com/expressjs/favicon) efficient favicon server (with default icon)
* - [logger](https://github.com/expressjs/morgan) request logger with custom format support
* - [methodOverride](https://github.com/expressjs/method-override) faux HTTP method support
* - [responseTime](https://github.com/expressjs/response-time) calculates response-time and exposes via X-Response-Time
* - [session](https://github.com/expressjs/session) session management support with bundled MemoryStore
* - [static](https://github.com/expressjs/serve-static) streaming static file server supporting `Range` and more
* - [timeout](https://github.com/expressjs/timeout) request timeouts
* - [vhost](https://github.com/expressjs/vhost) virtual host sub-domain mapping middleware
* - [bodyParser](bodyParser.html) extensible request body parser * - [bodyParser](bodyParser.html) extensible request body parser
* - [json](json.html) application/json parser * - [json](json.html) application/json parser
* - [urlencoded](urlencoded.html) application/x-www-form-urlencoded parser * - [urlencoded](urlencoded.html) application/x-www-form-urlencoded parser
* - [multipart](multipart.html) multipart/form-data parser * - [multipart](multipart.html) multipart/form-data parser
* - [timeout](timeout.html) request timeouts
* - [cookieParser](cookieParser.html) cookie parser
* - [session](session.html) session management support with bundled MemoryStore
* - [cookieSession](cookieSession.html) cookie-based session support * - [cookieSession](cookieSession.html) cookie-based session support
* - [methodOverride](methodOverride.html) faux HTTP method support
* - [responseTime](responseTime.html) calculates response-time and exposes via X-Response-Time
* - [staticCache](staticCache.html) memory cache layer for the static() middleware * - [staticCache](staticCache.html) memory cache layer for the static() middleware
* - [static](static.html) streaming static file server supporting `Range` and more
* - [directory](directory.html) directory listing middleware
* - [vhost](vhost.html) virtual host sub-domain mapping middleware
* - [favicon](favicon.html) efficient favicon server (with default icon)
* - [limit](limit.html) limit the bytesize of request bodies * - [limit](limit.html) limit the bytesize of request bodies
* - [query](query.html) automatic querystring parser, populating `req.query` * - [query](query.html) automatic querystring parser, populating `req.query`
* - [errorHandler](errorHandler.html) flexible error handler
* *
* Links: * Links:
* *
......
...@@ -5,102 +5,20 @@ ...@@ -5,102 +5,20 @@
* MIT Licensed * MIT Licensed
*/ */
/**
* Module dependencies.
*/
var utils = require('../utils')
, unauthorized = utils.unauthorized;
/** /**
* Basic Auth: * Basic Auth:
* *
* Status: Deprecated. No bug reports or pull requests are welcomed
* for this middleware. However, this middleware will not be removed.
* Instead, you should use [basic-auth](https://github.com/visionmedia/node-basic-auth).
*
* Enfore basic authentication by providing a `callback(user, pass)`, * Enfore basic authentication by providing a `callback(user, pass)`,
* which must return `true` in order to gain access. Alternatively an async * which must return `true` in order to gain access. Alternatively an async
* method is provided as well, invoking `callback(user, pass, callback)`. Populates * method is provided as well, invoking `callback(user, pass, callback)`. Populates
* `req.user`. The final alternative is simply passing username / password * `req.user`. The final alternative is simply passing username / password
* strings. * strings.
* *
* Simple username and password * See [basic-auth-connect](https://github.com/expressjs/basic-auth-connect)
*
* connect(connect.basicAuth('username', 'password'));
*
* Callback verification
*
* connect()
* .use(connect.basicAuth(function(user, pass){
* return 'tj' == user && 'wahoo' == pass;
* }))
*
* Async callback verification, accepting `fn(err, user)`.
*
* connect()
* .use(connect.basicAuth(function(user, pass, fn){
* User.authenticate({ user: user, pass: pass }, fn);
* }))
* *
* @param {Function|String} callback or username * @param {Function|String} callback or username
* @param {String} realm * @param {String} realm
* @api public * @api public
*/ */
module.exports = function basicAuth(callback, realm) { module.exports = require('basic-auth-connect');
var username, password;
// user / pass strings
if ('string' == typeof callback) {
username = callback;
password = realm;
if ('string' != typeof password) throw new Error('password argument required');
realm = arguments[2];
callback = function(user, pass){
return user == username && pass == password;
}
}
realm = realm || 'Authorization Required';
return function(req, res, next) {
var authorization = req.headers.authorization;
if (req.user) return next();
if (!authorization) return unauthorized(res, realm);
var parts = authorization.split(' ');
if (parts.length !== 2) return next(utils.error(400));
var scheme = parts[0]
, credentials = new Buffer(parts[1], 'base64').toString()
, index = credentials.indexOf(':');
if ('Basic' != scheme || index < 0) return next(utils.error(400));
var user = credentials.slice(0, index)
, pass = credentials.slice(index + 1);
// async
if (callback.length >= 3) {
var pause = utils.pause(req);
callback(user, pass, function(err, user){
if (err || !user) return unauthorized(res, realm);
req.user = req.remoteUser = user;
next();
pause.resume();
});
// sync
} else {
if (callback(user, pass)) {
req.user = req.remoteUser = user;
next();
} else {
unauthorized(res, realm);
}
}
}
};
...@@ -5,188 +5,16 @@ ...@@ -5,188 +5,16 @@
* MIT Licensed * MIT Licensed
*/ */
/**
* Module dependencies.
*/
var zlib = require('zlib');
var utils = require('../utils');
var Negotiator = require('negotiator');
/**
* Supported content-encoding methods.
*/
exports.methods = {
gzip: zlib.createGzip
, deflate: zlib.createDeflate
};
/**
* Default filter function.
*/
exports.filter = function(req, res){
return /json|text|javascript|dart|image\/svg\+xml|application\/x-font-ttf|application\/vnd\.ms-opentype|application\/vnd\.ms-fontobject/.test(res.getHeader('Content-Type'));
};
/** /**
* Compress: * Compress:
* *
* Compress response data with gzip/deflate. * Compress response data with gzip/deflate.
* *
* Filter: * See [compression](https://github.com/expressjs/compression)
*
* A `filter` callback function may be passed to
* replace the default logic of:
*
* exports.filter = function(req, res){
* return /json|text|javascript/.test(res.getHeader('Content-Type'));
* };
*
* Threshold:
*
* Only compress the response if the byte size is at or above a threshold.
* Always compress while streaming.
*
* - `threshold` - string representation of size or bytes as an integer.
*
* Options:
*
* All remaining options are passed to the gzip/deflate
* creation functions. Consult node's docs for additional details.
*
* - `chunkSize` (default: 16*1024)
* - `windowBits`
* - `level`: 0-9 where 0 is no compression, and 9 is slow but best compression
* - `memLevel`: 1-9 low is slower but uses less memory, high is fast but uses more
* - `strategy`: compression strategy
* *
* @param {Object} options * @param {Object} options
* @return {Function} * @return {Function}
* @api public * @api public
*/ */
module.exports = function compress(options) { module.exports = require('compression');
options = options || {};
var filter = options.filter || exports.filter;
var threshold;
if (false === options.threshold || 0 === options.threshold) {
threshold = 0
} else if ('string' === typeof options.threshold) {
threshold = utils.parseBytes(options.threshold)
} else {
threshold = options.threshold || 1024
}
return function compress(req, res, next){
var accept = req.headers['accept-encoding']
, write = res.write
, end = res.end
, compress = true
, stream;
// see #724
req.on('close', function(){
res.write = res.end = function(){};
});
// flush is noop by default
res.flush = noop;
// proxy
res.write = function(chunk, encoding){
if (!this.headerSent) {
// if content-length is set and is lower
// than the threshold, don't compress
var length = res.getHeader('content-length');
if (!isNaN(length) && length < threshold) compress = false;
this._implicitHeader();
}
return stream
? stream.write(new Buffer(chunk, encoding))
: write.call(res, chunk, encoding);
};
res.end = function(chunk, encoding){
if (chunk) {
if (!this.headerSent && getSize(chunk) < threshold) compress = false;
this.write(chunk, encoding);
} else if (!this.headerSent) {
// response size === 0
compress = false;
}
return stream
? stream.end()
: end.call(res);
};
res.on('header', function(){
// default request filter
if (!filter(req, res)) return;
// vary
var vary = res.getHeader('Vary');
if (!vary) {
res.setHeader('Vary', 'Accept-Encoding');
} else if (!~vary.indexOf('Accept-Encoding')) {
res.setHeader('Vary', vary + ', Accept-Encoding');
}
if (!compress) return;
var encoding = res.getHeader('Content-Encoding') || 'identity';
// already encoded
if ('identity' != encoding) return;
// SHOULD use identity
if (!accept) return;
// head
if ('HEAD' == req.method) return;
// compression method
var method = new Negotiator(req).preferredEncoding(['gzip', 'deflate', 'identity']);
// negotiation failed
if (method === 'identity') return;
// compression stream
stream = exports.methods[method](options);
// overwrite the flush method
res.flush = function(){
stream.flush();
}
// header fields
res.setHeader('Content-Encoding', method);
res.removeHeader('Content-Length');
// compression
stream.on('data', function(chunk){
write.call(res, chunk);
});
stream.on('end', function(){
end.call(res);
});
stream.on('drain', function() {
res.emit('drain');
});
});
next();
};
};
function getSize(chunk) {
return Buffer.isBuffer(chunk)
? chunk.length
: Buffer.byteLength(chunk);
}
function noop(){}
...@@ -6,62 +6,14 @@ ...@@ -6,62 +6,14 @@
* MIT Licensed * MIT Licensed
*/ */
/**
* Module dependencies.
*/
var utils = require('./../utils')
, cookie = require('cookie');
/** /**
* Cookie parser: * Cookie parser:
* *
* Status: Deprecated. This middleware will be removed in * See [cookie-parser](https://github.com/expressjs/cookie-parser)
* Connect 3.0 and will be replaced by a `cookies` middleware,
* which will use [cookies](http://github.com/jed/cookies)
* and [keygrip](https://github.com/jed/keygrip).
*
* Parse _Cookie_ header and populate `req.cookies`
* with an object keyed by the cookie names. Optionally
* you may enabled signed cookie support by passing
* a `secret` string, which assigns `req.secret` so
* it may be used by other middleware.
*
* Examples:
*
* connect()
* .use(connect.cookieParser('optional secret string'))
* .use(function(req, res, next){
* res.end(JSON.stringify(req.cookies));
* })
* *
* @param {String} secret * @param {String} secret
* @return {Function} * @return {Function}
* @api public * @api public
*/ */
module.exports = function cookieParser(secret, opt){ module.exports = require('cookie-parser');
return function cookieParser(req, res, next) {
if (req.cookies) return next();
var cookies = req.headers.cookie;
req.secret = secret;
req.cookies = {};
req.signedCookies = {};
if (cookies) {
try {
req.cookies = cookie.parse(cookies, opt);
if (secret) {
req.signedCookies = utils.parseSignedCookies(req.cookies, secret);
req.signedCookies = utils.parseJSONCookies(req.signedCookies);
}
req.cookies = utils.parseJSONCookies(req.cookies);
} catch (err) {
err.status = 400;
return next(err);
}
}
next();
};
};
...@@ -9,10 +9,9 @@ ...@@ -9,10 +9,9 @@
*/ */
var utils = require('./../utils') var utils = require('./../utils')
, Cookie = require('./session/cookie') , Cookie = require('express-session').Cookie
, debug = require('debug')('connect:cookieSession') , debug = require('debug')('connect:cookieSession')
, signature = require('cookie-signature') , signature = require('cookie-signature')
, crc32 = require('buffer-crc32')
, url = require('url'); , url = require('url');
/** /**
...@@ -78,7 +77,7 @@ module.exports = function cookieSession(options){ ...@@ -78,7 +77,7 @@ module.exports = function cookieSession(options){
if (rawCookie) { if (rawCookie) {
var unsigned = utils.parseSignedCookie(rawCookie, secret); var unsigned = utils.parseSignedCookie(rawCookie, secret);
if (unsigned) { if (unsigned) {
var originalHash = crc32.signed(unsigned); var original = unsigned;
req.session = utils.parseJSONCookie(unsigned) || {}; req.session = utils.parseJSONCookie(unsigned) || {};
req.session.cookie = cookie; req.session.cookie = cookie;
} }
...@@ -107,8 +106,8 @@ module.exports = function cookieSession(options){ ...@@ -107,8 +106,8 @@ module.exports = function cookieSession(options){
debug('serializing %j', req.session); debug('serializing %j', req.session);
var val = 'j:' + JSON.stringify(req.session); var val = 'j:' + JSON.stringify(req.session);
// compare hashes, no need to set-cookie if unchanged // compare data, no need to set-cookie if unchanged
if (originalHash == crc32.signed(val)) return debug('unmodified session'); if (original == val) return debug('unmodified session');
// set-cookie // set-cookie
val = 's:' + signature.sign(val, secret); val = 's:' + signature.sign(val, secret);
......
...@@ -4,160 +4,15 @@ ...@@ -4,160 +4,15 @@
* MIT Licensed * MIT Licensed
*/ */
/**
* Module dependencies.
*/
var utils = require('../utils');
var uid = require('uid2');
var crypto = require('crypto');
/** /**
* Anti CSRF: * Anti CSRF:
* *
* CSRF protection middleware. * CSRF protection middleware.
* *
* This middleware adds a `req.csrfToken()` function to make a token * See [csurf](https://github.com/expressjs/csurf)
* 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 session.
*
* The default `value` function checks `req.body` generated
* by the `bodyParser()` middleware, `req.query` generated
* by `query()`, and the "X-CSRF-Token" header field.
*
* This middleware requires session support, thus should be added
* somewhere _below_ `session()` and `cookieParser()`.
*
* Options:
*
* - `value` a function accepting the request, returning the token
* *
* @param {Object} options * @param {Object} options
* @api public * @api public
*/ */
module.exports = function csrf(options) { module.exports = require('csurf');
options = options || {};
var value = options.value || defaultValue;
return function(req, res, next){
// already have one
var secret = req.session._csrfSecret;
if (secret) return createToken(secret);
// generate secret
uid(24, function(err, secret){
if (err) return next(err);
req.session._csrfSecret = secret;
createToken(secret);
});
// generate the token
function createToken(secret) {
var token;
// lazy-load token
req.csrfToken = function csrfToken() {
return token || (token = saltedToken(secret));
};
// compatibility with old middleware
Object.defineProperty(req.session, '_csrf', {
configurable: true,
get: function() {
console.warn('req.session._csrf is deprecated, use req.csrfToken() instead');
return req.csrfToken();
}
});
// ignore these methods
if ('GET' == req.method || 'HEAD' == req.method || 'OPTIONS' == req.method) return next();
// determine user-submitted value
var val = value(req);
// check
if (!checkToken(val, secret)) return next(utils.error(403));
next();
}
}
};
/**
* Default value function, checking the `req.body`
* and `req.query` for the CSRF token.
*
* @param {IncomingMessage} req
* @return {String}
* @api private
*/
function defaultValue(req) {
return (req.body && req.body._csrf)
|| (req.query && req.query._csrf)
|| (req.headers['x-csrf-token'])
|| (req.headers['x-xsrf-token']);
}
/**
* Return salted token.
*
* @param {String} secret
* @return {String}
* @api private
*/
function saltedToken(secret) {
return createToken(generateSalt(10), secret);
}
/**
* Creates a CSRF token from a given salt and secret.
*
* @param {String} salt (should be 10 characters)
* @param {String} secret
* @return {String}
* @api private
*/
function createToken(salt, secret) {
return salt + crypto
.createHash('sha1')
.update(salt + secret)
.digest('base64');
}
/**
* Checks if a given CSRF token matches the given secret.
*
* @param {String} token
* @param {String} secret
* @return {Boolean}
* @api private
*/
function checkToken(token, secret) {
if ('string' != typeof token) return false;
return token === createToken(token.slice(0, 10), secret);
}
/**
* Generates a random salt, using a fast non-blocking PRNG (Math.random()).
*
* @param {Number} length
* @return {String}
* @api private
*/
function generateSalt(length) {
var i, r = [];
for (i = 0; i < length; ++i) {
r.push(SALTCHARS[Math.floor(Math.random() * SALTCHARS.length)]);
}
return r.join('');
}
var SALTCHARS = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789';
...@@ -6,56 +6,10 @@ ...@@ -6,56 +6,10 @@
* MIT Licensed * MIT Licensed
*/ */
// 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
, sep = path.sep
, extname = path.extname
, join = path.join;
var Batch = require('batch');
var Negotiator = require('negotiator');
/*!
* Icon cache.
*/
var cache = {};
/**
* Media types and the map for content negotiation.
*/
var mediaTypes = [
'text/html',
'text/plain',
'application/json'
];
var mediaType = {
'text/html': 'html',
'text/plain': 'plain',
'application/json': 'json'
};
/** /**
* Directory: * Directory:
* *
* Serve directory listings with the given `root` path. * See [serve-index](https://github.com/expressjs/serve-index)
*
* 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 {String} root
* @param {Object} options * @param {Object} options
...@@ -63,268 +17,4 @@ var mediaType = { ...@@ -63,268 +17,4 @@ var mediaType = {
* @api public * @api public
*/ */
exports = module.exports = function directory(root, options){ module.exports = require('serve-index');
options = options || {};
// root required
if (!root) throw new Error('directory() root path required');
var hidden = options.hidden
, icons = options.icons
, view = options.view || 'tiles'
, filter = options.filter
, root = normalize(root + sep);
return function directory(req, res, next) {
if ('GET' != req.method && 'HEAD' != req.method) return next();
var url = parse(req.url)
, dir = decodeURIComponent(url.pathname)
, path = normalize(join(root, dir))
, originalUrl = parse(req.originalUrl)
, originalDir = decodeURIComponent(originalUrl.pathname)
, showUp = path != root;
// null byte(s), bad request
if (~path.indexOf('\0')) return next(utils.error(400));
// malicious path, forbidden
if (0 != path.indexOf(root)) return next(utils.error(403));
// check if we have a directory
fs.stat(path, function(err, stat){
if (err) return 'ENOENT' == err.code
? next()
: next(err);
if (!stat.isDirectory()) return next();
// fetch files
fs.readdir(path, function(err, files){
if (err) return next(err);
if (!hidden) files = removeHidden(files);
if (filter) files = files.filter(filter);
files.sort();
// content-negotiation
var type = new Negotiator(req).preferredMediaType(mediaTypes);
// not acceptable
if (!type) return next(utils.error(406));
exports[mediaType[type]](req, res, files, next, originalDir, showUp, icons, path, view);
});
});
};
};
/**
* Respond with text/html.
*/
exports.html = function(req, res, files, next, dir, showUp, icons, path, view){
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);
stat(path, files, function(err, stats){
if (err) return next(err);
files = files.map(function(file, i){ return { name: file, stat: stats[i] }; });
files.sort(fileSort);
if (showUp) files.unshift({ name: '..' });
str = str
.replace('{style}', style.concat(iconStyle(files, icons)))
.replace('{files}', html(files, dir, icons, view))
.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);
};
/**
* Sort function for with directories first.
*/
function fileSort(a, b) {
return Number(b.stat && b.stat.isDirectory()) - Number(a.stat && a.stat.isDirectory()) ||
String(a.name).toLocaleLowerCase().localeCompare(String(b.name).toLocaleLowerCase());
}
/**
* Map html `dir`, returning a linked path.
*/
function htmlPath(dir) {
var curr = [];
return dir.split('/').map(function(part){
curr.push(encodeURIComponent(part));
return part ? '<a href="' + curr.join('/') + '">' + part + '</a>' : '';
}).join(' / ');
}
/**
* Load icon images, return css string.
*/
function iconStyle (files, useIcons) {
if (!useIcons) return '';
var data = {};
var views = { tiles: [], details: [], mobile: [] };
for (var i=0; i < files.length; i++) {
var file = files[i];
if (file.name == '..') continue;
var isDir = '..' == file.name || (file.stat && file.stat.isDirectory());
var icon = isDir ? icons.folder : icons[extname(file.name)] || icons.default;
var ext = extname(file.name);
ext = isDir ? '.directory' : (icons[ext] ? ext : '.default');
if (data[icon]) continue;
data[icon] = ext + ' .name{background-image: url(data:image/png;base64,' + load(icon)+');}';
views.tiles.push('.view-tiles ' + data[icon]);
views.details.push('.view-details ' + data[icon]);
views.mobile.push('#files ' + data[icon]);
}
var style = views.tiles.join('\n')
+ '\n'+views.details.join('\n')
+ '\n@media (max-width: 768px) {\n\t'
+ views.mobile.join('\n\t')
+ '\n}';
return style;
}
/**
* Map html `files`, returning an html unordered list.
*/
function html(files, dir, useIcons, view) {
return '<ul id="files" class="view-'+view+'">'
+ (view == 'details' ? (
'<li class="header">'
+ '<span class="name">Name</span>'
+ '<span class="size">Size</span>'
+ '<span class="date">Modified</span>'
+ '</li>') : '')
+ files.map(function(file){
var isDir
, classes = []
, path = dir.split('/').map(function (c) { return encodeURIComponent(c); });
if (useIcons) {
var ext = extname(file.name);
isDir = '..' == file.name || (file.stat && file.stat.isDirectory());
ext = isDir ? '.directory' : (icons[ext] ? ext : '.default');
classes.push('icon');
classes.push(ext.replace('.',''));
}
path.push(encodeURIComponent(file.name));
var date = file.name == '..' ? ''
: file.stat.mtime.toDateString()+' '+file.stat.mtime.toLocaleTimeString();
var size = file.name == '..' ? '' : file.stat.size;
return '<li><a href="'
+ utils.normalizeSlashes(normalize(path.join('/')))
+ '" class="'
+ classes.join(' ') + '"'
+ ' title="' + file.name + '">'
+ '<span class="name">'+file.name+'</span>'
+ '<span class="size">'+size+'</span>'
+ '<span class="date">'+date+'</span>'
+ '</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];
});
}
/**
* Stat all files and return array of stat
* in same order.
*/
function stat(dir, files, cb) {
var batch = new Batch();
batch.concurrency(10);
files.forEach(function(file, i){
batch.push(function(done){
fs.stat(join(dir, file), done);
});
});
batch.end(cb);
}
/**
* 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'
, 'folder': 'folder.png'
, 'default': 'page_white.png'
};
...@@ -5,82 +5,13 @@ ...@@ -5,82 +5,13 @@
* MIT Licensed * MIT Licensed
*/ */
/**
* Module dependencies.
*/
var utils = require('../utils')
, fs = require('fs');
// environment
var env = process.env.NODE_ENV || 'development';
/** /**
* Error handler: * Error handler:
* *
* Development error handler, providing stack traces * See [errorHandler](https://github.com/expressjs/errorhandler)
* and error message responses for requests accepting text, html,
* or json.
*
* Text:
*
* By default, and when _text/plain_ is accepted a simple stack trace
* or error message will be returned.
*
* JSON:
*
* When _application/json_ is accepted, connect will respond with
* an object in the form of `{ "error": error }`.
*
* HTML:
*
* When accepted connect will output a nice html stack trace.
* *
* @return {Function} * @return {Function}
* @api public * @api public
*/ */
exports = module.exports = function errorHandler(){ module.exports = require('errorhandler');
return function errorHandler(err, req, res, next){
if (err.status) res.statusCode = err.status;
if (res.statusCode < 400) res.statusCode = 500;
if ('test' != env) console.error(err.stack);
var accept = req.headers.accept || '';
// html
if (~accept.indexOf('html')) {
fs.readFile(__dirname + '/../public/style.css', 'utf8', function(e, style){
fs.readFile(__dirname + '/../public/error.html', 'utf8', function(e, html){
var stack = (err.stack || '')
.split('\n').slice(1)
.map(function(v){ return '<li>' + v + '</li>'; }).join('');
html = html
.replace('{style}', style)
.replace('{stack}', stack)
.replace('{title}', exports.title)
.replace('{statusCode}', res.statusCode)
.replace(/\{error\}/g, utils.escape(err.toString().replace(/\n/g, '<br/>')));
res.setHeader('Content-Type', 'text/html; charset=utf-8');
res.end(html);
});
});
// json
} else if (~accept.indexOf('json')) {
var error = { message: err.message, stack: err.stack };
for (var prop in err) error[prop] = err[prop];
var json = JSON.stringify({ error: error });
res.setHeader('Content-Type', 'application/json');
res.end(json);
// plain text
} else {
res.setHeader('Content-Type', 'text/plain');
res.end(err.stack);
}
};
};
/**
* Template title, framework authors may override this value.
*/
exports.title = 'Connect';
...@@ -5,40 +5,13 @@ ...@@ -5,40 +5,13 @@
* MIT Licensed * MIT Licensed
*/ */
/**
* Module dependencies.
*/
var fs = require('fs')
, utils = require('../utils');
/** /**
* Favicon: * Favicon:
* *
* By default serves the connect favicon, or the favicon * By default serves the connect favicon, or the favicon
* located by the given `path`. * located by the given `path`.
* *
* Options: * See [static-favicon](https://github.com/expressjs/favicon)
*
* - `maxAge` cache-control max-age directive, defaulting to 1 day
*
* Examples:
*
* Serve default favicon:
*
* connect()
* .use(connect.favicon())
*
* Serve favicon before logging for brevity:
*
* connect()
* .use(connect.favicon())
* .use(connect.logger('dev'))
*
* Serve custom favicon:
*
* connect()
* .use(connect.favicon('public/favicon.ico'))
* *
* @param {String} path * @param {String} path
* @param {Object} options * @param {Object} options
...@@ -46,35 +19,4 @@ var fs = require('fs') ...@@ -46,35 +19,4 @@ var fs = require('fs')
* @api public * @api public
*/ */
module.exports = function favicon(path, options){ module.exports = require('static-favicon');
var options = options || {}
, path = path || __dirname + '/../public/favicon.ico'
, maxAge = options.maxAge || 86400000
, icon; // favicon cache
return function favicon(req, res, next){
if ('/favicon.ico' == req.url) {
if (icon) {
res.writeHead(200, icon.headers);
res.end(icon.body);
} else {
fs.readFile(path, function(err, buf){
if (err) return next(err);
icon = {
headers: {
'Content-Type': 'image/x-icon'
, 'Content-Length': buf.length
, 'ETag': '"' + utils.md5(buf) + '"'
, 'Cache-Control': 'public, max-age=' + (maxAge / 1000)
},
body: buf
};
res.writeHead(200, icon.headers);
res.end(icon.body);
});
}
} else {
next();
}
};
};
...@@ -5,338 +5,16 @@ ...@@ -5,338 +5,16 @@
* MIT Licensed * MIT Licensed
*/ */
/**
* Module dependencies.
*/
var bytes = require('bytes');
/*!
* Log buffer.
*/
var buf = [];
/*!
* Default log buffer duration.
*/
var defaultBufferDuration = 1000;
/** /**
* Logger: * Logger:
* *
* Log requests with the given `options` or a `format` string. * Log requests with the given `options` or a `format` string.
* *
* Options: * See [morgan](https://github.com/expressjs/morgan)
*
* - `format` Format string, see below for tokens
* - `stream` Output stream, defaults to _stdout_
* - `buffer` Buffer duration, defaults to 1000ms when _true_
* - `immediate` Write log line on request instead of response (for response times)
*
* Tokens:
*
* - `:req[header]` ex: `:req[Accept]`
* - `:res[header]` ex: `:res[Content-Length]`
* - `:http-version`
* - `:response-time`
* - `:remote-addr`
* - `:date`
* - `:method`
* - `:url`
* - `:referrer`
* - `:user-agent`
* - `:status`
*
* Formats:
*
* Pre-defined formats that ship with connect:
*
* - `default` ':remote-addr - - [:date] ":method :url HTTP/:http-version" :status :res[content-length] ":referrer" ":user-agent"'
* - `short` ':remote-addr - :method :url HTTP/:http-version :status :res[content-length] - :response-time ms'
* - `tiny` ':method :url :status :res[content-length] - :response-time ms'
* - `dev` concise output colored by response status for development use
*
* Examples:
*
* connect.logger() // default
* connect.logger('short')
* connect.logger('tiny')
* connect.logger({ immediate: true, format: 'dev' })
* connect.logger(':method :url - :referrer')
* connect.logger(':req[content-type] -> :res[content-type]')
* connect.logger(function(tokens, req, res){ return 'some format string' })
*
* Defining Tokens:
*
* To define a token, simply invoke `connect.logger.token()` with the
* name and a callback function. The value returned is then available
* as ":type" in this case.
*
* connect.logger.token('type', function(req, res){ return req.headers['content-type']; })
*
* Defining Formats:
*
* All default formats are defined this way, however it's public API as well:
*
* connect.logger.format('name', 'string or function')
* *
* @param {String|Function|Object} format or options * @param {String|Function|Object} format or options
* @return {Function} * @return {Function}
* @api public * @api public
*/ */
exports = module.exports = function logger(options) { module.exports = require('morgan');
if ('object' == typeof options) {
options = options || {};
} else if (options) {
options = { format: options };
} else {
options = {};
}
// output on request instead of response
var immediate = options.immediate;
// format name
var fmt = exports[options.format] || options.format || exports.default;
// compile format
if ('function' != typeof fmt) fmt = compile(fmt);
// options
var stream = options.stream || process.stdout
, buffer = options.buffer;
// buffering support
if (buffer) {
var realStream = stream
, interval = 'number' == typeof buffer
? buffer
: defaultBufferDuration;
// flush interval
setInterval(function(){
if (buf.length) {
realStream.write(buf.join(''));
buf.length = 0;
}
}, interval);
// swap the stream
stream = {
write: function(str){
buf.push(str);
}
};
}
return function logger(req, res, next) {
var sock = req.socket;
req._startTime = new Date;
req._remoteAddress = sock.socket ? sock.socket.remoteAddress : sock.remoteAddress;
function logRequest(){
res.removeListener('finish', logRequest);
res.removeListener('close', logRequest);
var line = fmt(exports, req, res);
if (null == line) return;
stream.write(line + '\n');
};
// immediate
if (immediate) {
logRequest();
// proxy end to output logging
} else {
res.on('finish', logRequest);
res.on('close', logRequest);
}
next();
};
};
/**
* Compile `fmt` into a function.
*
* @param {String} fmt
* @return {Function}
* @api private
*/
function compile(fmt) {
fmt = fmt.replace(/"/g, '\\"');
var js = ' return "' + fmt.replace(/:([-\w]{2,})(?:\[([^\]]+)\])?/g, function(_, name, arg){
return '"\n + (tokens["' + name + '"](req, res, "' + arg + '") || "-") + "';
}) + '";'
return new Function('tokens, req, res', js);
};
/**
* Define a token function with the given `name`,
* and callback `fn(req, res)`.
*
* @param {String} name
* @param {Function} fn
* @return {Object} exports for chaining
* @api public
*/
exports.token = function(name, fn) {
exports[name] = fn;
return this;
};
/**
* Define a `fmt` with the given `name`.
*
* @param {String} name
* @param {String|Function} fmt
* @return {Object} exports for chaining
* @api public
*/
exports.format = function(name, str){
exports[name] = str;
return this;
};
/**
* Default format.
*/
exports.format('default', ':remote-addr - - [:date] ":method :url HTTP/:http-version" :status :res[content-length] ":referrer" ":user-agent"');
/**
* Short format.
*/
exports.format('short', ':remote-addr - :method :url HTTP/:http-version :status :res[content-length] - :response-time ms');
/**
* Tiny format.
*/
exports.format('tiny', ':method :url :status :res[content-length] - :response-time ms');
/**
* dev (colored)
*/
exports.format('dev', function(tokens, req, res){
var status = res.statusCode
, len = parseInt(res.getHeader('Content-Length'), 10)
, color = 32;
if (status >= 500) color = 31
else if (status >= 400) color = 33
else if (status >= 300) color = 36;
len = isNaN(len)
? ''
: len = ' - ' + bytes(len);
return '\x1b[90m' + req.method
+ ' ' + req.originalUrl + ' '
+ '\x1b[' + color + 'm' + res.statusCode
+ ' \x1b[90m'
+ (new Date - req._startTime)
+ 'ms' + len
+ '\x1b[0m';
});
/**
* request url
*/
exports.token('url', function(req){
return req.originalUrl || req.url;
});
/**
* request method
*/
exports.token('method', function(req){
return req.method;
});
/**
* response time in milliseconds
*/
exports.token('response-time', function(req){
return String(Date.now() - req._startTime);
});
/**
* UTC date
*/
exports.token('date', function(){
return new Date().toUTCString();
});
/**
* response status code
*/
exports.token('status', function(req, res){
return res.headerSent ? res.statusCode : null;
});
/**
* normalized referrer
*/
exports.token('referrer', function(req){
return req.headers['referer'] || req.headers['referrer'];
});
/**
* remote address
*/
exports.token('remote-addr', function(req){
if (req.ip) return req.ip;
if (req._remoteAddress) return req._remoteAddress;
var sock = req.socket;
if (sock.socket) return sock.socket.remoteAddress;
return sock.remoteAddress;
});
/**
* HTTP version
*/
exports.token('http-version', function(req){
return req.httpVersionMajor + '.' + req.httpVersionMinor;
});
/**
* UA string
*/
exports.token('user-agent', function(req){
return req.headers['user-agent'];
});
/**
* request header
*/
exports.token('req', function(req, res, field){
return req.headers[field.toLowerCase()];
});
/**
* response header
*/
exports.token('res', function(req, res, field){
return (res._headers || {})[field.toLowerCase()];
});
...@@ -5,54 +5,14 @@ ...@@ -5,54 +5,14 @@
* MIT Licensed * MIT Licensed
*/ */
/**
* Module dependencies.
*/
var methods = require('methods');
/** /**
* Method Override: * Method Override:
* *
* Provides faux HTTP method support. * See [method-override](https://github.com/expressjs/method-override)
*
* Pass an optional `key` to use when checking for
* a method override, otherwise defaults to _\_method_.
* The original method is available via `req.originalMethod`.
* *
* @param {String} key * @param {String} key
* @return {Function} * @return {Function}
* @api public * @api public
*/ */
module.exports = function methodOverride(key){ module.exports = require('method-override');
key = key || "_method";
return function methodOverride(req, res, next) {
var method;
req.originalMethod = req.originalMethod || req.method;
// req.body
if (req.body && typeof req.body === 'object' && key in req.body) {
method = req.body[key].toLowerCase();
delete req.body[key];
}
// check X-HTTP-Method-Override
if (req.headers['x-http-method-override']) {
method = req.headers['x-http-method-override'].toLowerCase();
}
// replace
if (supports(method)) req.method = method.toUpperCase();
next();
};
};
/**
* Check if node supports `method`.
*/
function supports(method) {
return ~methods.indexOf(method);
}
...@@ -8,25 +8,10 @@ ...@@ -8,25 +8,10 @@
/** /**
* Reponse time: * Reponse time:
* *
* Adds the `X-Response-Time` header displaying the response * See [response-time](https://github.com/expressjs/response-time)
* duration in milliseconds.
* *
* @return {Function} * @return {Function}
* @api public * @api public
*/ */
module.exports = function responseTime(){ module.exports = require('response-time');
return function(req, res, next){
var start = new Date;
if (res._responseTime) return next();
res._responseTime = true;
res.on('header', function(){
var duration = new Date - start;
res.setHeader('X-Response-Time', duration + 'ms');
});
next();
};
};
...@@ -5,36 +5,10 @@ ...@@ -5,36 +5,10 @@
* MIT Licensed * MIT Licensed
*/ */
/**
* Module dependencies.
*/
var send = require('send')
, utils = require('../utils')
, parse = utils.parseUrl
, url = require('url');
/** /**
* Static: * Static:
* *
* Static file server with the given `root` path. * See [serve-static](https://github.com/expressjs/serve-static)
*
* Examples:
*
* var oneDay = 86400000;
*
* connect()
* .use(connect.static(__dirname + '/public'))
*
* connect()
* .use(connect.static(__dirname + '/public', { maxAge: oneDay }))
*
* Options:
*
* - `maxAge` Browser cache maxAge in milliseconds. defaults to 0
* - `hidden` Allow transfer of hidden files. defaults to false
* - `redirect` Redirect to trailing "/" when the pathname is a dir. defaults to true
* - `index` Default file name, defaults to 'index.html'
* *
* @param {String} root * @param {String} root
* @param {Object} options * @param {Object} options
...@@ -42,61 +16,4 @@ var send = require('send') ...@@ -42,61 +16,4 @@ var send = require('send')
* @api public * @api public
*/ */
exports = module.exports = function(root, options){ module.exports = require('serve-static');
options = options || {};
// root required
if (!root) throw new Error('static() root path required');
// default redirect
var redirect = false !== options.redirect;
return function staticMiddleware(req, res, next) {
if ('GET' != req.method && 'HEAD' != req.method) return next();
var originalUrl = url.parse(req.originalUrl);
var path = parse(req).pathname;
var pause = utils.pause(req);
if (path == '/' && originalUrl.pathname[originalUrl.pathname.length - 1] != '/') {
return directory();
}
function resume() {
next();
pause.resume();
}
function directory() {
if (!redirect) return resume();
var target;
originalUrl.pathname += '/';
target = url.format(originalUrl);
res.statusCode = 303;
res.setHeader('Location', target);
res.end('Redirecting to ' + utils.escape(target));
}
function error(err) {
if (404 == err.status) return resume();
next(err);
}
send(req, path)
.maxage(options.maxAge || 0)
.root(root)
.index(options.index || 'index.html')
.hidden(options.hidden)
.on('error', error)
.on('directory', directory)
.pipe(res);
};
};
/**
* Expose mime module.
*
* If you wish to extend the mime table use this
* reference to the "mime" module in the npm registry.
*/
exports.mime = send.mime;
...@@ -13,43 +13,11 @@ var debug = require('debug')('connect:timeout'); ...@@ -13,43 +13,11 @@ var debug = require('debug')('connect:timeout');
/** /**
* Timeout: * Timeout:
* *
* Times out the request in `ms`, defaulting to `5000`. The * See [connect-timeout](https://github.com/expressjs/timeout)
* method `req.clearTimeout()` is added to revert this behaviour
* programmatically within your application's middleware, routes, etc.
*
* The timeout error is passed to `next()` so that you may customize
* the response behaviour. This error has the `.timeout` property as
* well as `.status == 503`.
* *
* @param {Number} ms * @param {Number} ms
* @return {Function} * @return {Function}
* @api public * @api public
*/ */
module.exports = function timeout(ms) { module.exports = require('connect-timeout');
ms = ms || 5000;
return function(req, res, next) {
var id = setTimeout(function(){
req.emit('timeout', ms);
}, ms);
req.on('timeout', function(){
if (res.headerSent) return debug('response started, cannot timeout');
var err = new Error('Response timeout');
err.timeout = ms;
err.status = 503;
next(err);
});
req.clearTimeout = function(){
clearTimeout(id);
};
res.on('header', function(){
clearTimeout(id);
});
next();
};
};
/*! /*!
* Connect - urlencoded * Connect - urlencoded
* Copyright(c) 2010 Sencha Inc. * Copyright(c) 2010 Sencha Inc.
...@@ -65,7 +64,7 @@ exports = module.exports = function(options){ ...@@ -65,7 +64,7 @@ exports = module.exports = function(options){
try { try {
req.body = buf.length req.body = buf.length
? qs.parse(buf, options) ? qs.parse(buf)
: {}; : {};
} catch (err){ } catch (err){
err.body = buf; err.body = buf;
......
...@@ -9,15 +9,7 @@ ...@@ -9,15 +9,7 @@
/** /**
* Vhost: * Vhost:
* *
* Setup vhost for the given `hostname` and `server`. * See [vhost](https://github.com/expressjs/vhost)
*
* connect()
* .use(connect.vhost('foo.com', fooApp))
* .use(connect.vhost('bar.com', barApp))
* .use(connect.vhost('*.com', mainApp))
*
* The `server` may be a Connect server or
* a regular Node `http.Server`.
* *
* @param {String} hostname * @param {String} hostname
* @param {Server} server * @param {Server} server
...@@ -25,16 +17,4 @@ ...@@ -25,16 +17,4 @@
* @api public * @api public
*/ */
module.exports = function vhost(hostname, server){ module.exports = require('vhost');
if (!hostname) throw new Error('vhost hostname required');
if (!server) throw new Error('vhost server required');
var regexp = new RegExp('^' + hostname.replace(/[^*\w]/g, '\\$&').replace(/[*]/g, '(?:.*?)') + '$', 'i');
if (server.onvhost) server.onvhost(hostname);
return function vhost(req, res, next){
if (!req.headers.host) return next();
var host = req.headers.host.split(':')[0];
if (!regexp.test(host)) return next();
if ('function' == typeof server) return server(req, res, next);
server.emit('request', req, res);
};
};
...@@ -45,8 +45,9 @@ exports.hasBody = function(req) { ...@@ -45,8 +45,9 @@ exports.hasBody = function(req) {
*/ */
exports.mime = function(req) { exports.mime = function(req) {
var str = req.headers['content-type'] || ''; var str = req.headers['content-type'] || ''
return str.split(';')[0]; , i = str.indexOf(';');
return ~i ? str.slice(0, i) : str;
}; };
/** /**
......
BIN = ./node_modules/.bin/
test:
@NODE_ENV=test $(BIN)mocha \
--require should \
--reporter spec
.PHONY: test
\ No newline at end of file
# simgr - Simple Image Resizer [![Build Status](https://travis-ci.org/expressjs/basic-auth-connect.png)](https://travis-ci.org/expressjs/basic-auth-connect)
Connect's Basic Auth middleware in its own module. This module is considered deprecated. You should instead create your own middleware with [basic-auth](https://github.com/visionmedia/node-basic-auth).
## API
```js
var basicAuth = require('basic-auth-connect');
```
Sorry, couldn't think of a more clever name.
Simple username and password
```js
connect()
.use(basicAuth('username', 'password'));
```
Callback verification
```js
connect()
.use(basicAuth(function(user, pass){
return 'tj' == user && 'wahoo' == pass;
}))
```
Async callback verification, accepting `fn(err, user)`.
```
connect()
.use(basicAuth(function(user, pass, fn){
User.authenticate({ user: user, pass: pass }, fn);
}))
```
## License
The MIT License (MIT)
Copyright (c) 2013 Jonathan Ong me@jongleberry.com
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.
\ No newline at end of file
var http = require('http');
/*!
* Connect - basicAuth
* Copyright(c) 2010 Sencha Inc.
* Copyright(c) 2011 TJ Holowaychuk
* MIT Licensed
*/
/**
* Basic Auth:
*
* Status: Deprecated. No bug reports or pull requests are welcomed
* for this middleware. However, this middleware will not be removed.
* Instead, you should use [basic-auth](https://github.com/visionmedia/node-basic-auth).
*
* Enfore basic authentication by providing a `callback(user, pass)`,
* which must return `true` in order to gain access. Alternatively an async
* method is provided as well, invoking `callback(user, pass, callback)`. Populates
* `req.user`. The final alternative is simply passing username / password
* strings.
*
* Simple username and password
*
* connect(connect.basicAuth('username', 'password'));
*
* Callback verification
*
* connect()
* .use(connect.basicAuth(function(user, pass){
* return 'tj' == user && 'wahoo' == pass;
* }))
*
* Async callback verification, accepting `fn(err, user)`.
*
* connect()
* .use(connect.basicAuth(function(user, pass, fn){
* User.authenticate({ user: user, pass: pass }, fn);
* }))
*
* @param {Function|String} callback or username
* @param {String} realm
* @api public
*/
module.exports = function basicAuth(callback, realm) {
var username, password;
// user / pass strings
if ('string' == typeof callback) {
username = callback;
password = realm;
if ('string' != typeof password) throw new Error('password argument required');
realm = arguments[2];
callback = function(user, pass){
return user == username && pass == password;
}
}
realm = realm || 'Authorization Required';
return function(req, res, next) {
var authorization = req.headers.authorization;
if (req.user) return next();
if (!authorization) return unauthorized(res, realm);
var parts = authorization.split(' ');
if (parts.length !== 2) return next(error(400));
var scheme = parts[0]
, credentials = new Buffer(parts[1], 'base64').toString()
, index = credentials.indexOf(':');
if ('Basic' != scheme || index < 0) return next(error(400));
var user = credentials.slice(0, index)
, pass = credentials.slice(index + 1);
// async
if (callback.length >= 3) {
callback(user, pass, function(err, user){
if (err || !user) return unauthorized(res, realm);
req.user = req.remoteUser = user;
next();
});
// sync
} else {
if (callback(user, pass)) {
req.user = req.remoteUser = user;
next();
} else {
unauthorized(res, realm);
}
}
}
};
/**
* Respond with 401 "Unauthorized".
*
* @param {ServerResponse} res
* @param {String} realm
* @api private
*/
function unauthorized(res, realm) {
res.statusCode = 401;
res.setHeader('WWW-Authenticate', 'Basic realm="' + realm + '"');
res.end('Unauthorized');
};
/**
* Generate an `Error` from the given status `code`
* and optional `msg`.
*
* @param {Number} code
* @param {String} msg
* @return {Error}
* @api private
*/
function error(code, msg){
var err = new Error(msg || http.STATUS_CODES[code]);
err.status = code;
return err;
};
\ No newline at end of file
{
"name": "basic-auth-connect",
"description": "Basic auth middleware for node and connect",
"version": "1.0.0",
"author": {
"name": "Jonathan Ong",
"email": "me@jongleberry.com",
"url": "http://jongleberry.com"
},
"license": "MIT",
"repository": {
"type": "git",
"url": "https://github.com/expressjs/basic-auth-connect.git"
},
"bugs": {
"url": "https://github.com/expressjs/basic-auth-connect/issues"
},
"devDependencies": {
"mocha": "*",
"should": "*",
"supertest": "*",
"connect": "*"
},
"scripts": {
"test": "make test"
},
"readme": "# simgr - Simple Image Resizer [![Build Status](https://travis-ci.org/expressjs/basic-auth-connect.png)](https://travis-ci.org/expressjs/basic-auth-connect)\n\nConnect's Basic Auth middleware in its own module. This module is considered deprecated. You should instead create your own middleware with [basic-auth](https://github.com/visionmedia/node-basic-auth).\n\n## API\n\n```js\nvar basicAuth = require('basic-auth-connect');\n```\n\nSorry, couldn't think of a more clever name.\n\nSimple username and password\n\n```js\nconnect()\n.use(basicAuth('username', 'password'));\n```\n\nCallback verification\n\n```js\nconnect()\n.use(basicAuth(function(user, pass){\n return 'tj' == user && 'wahoo' == pass;\n}))\n```\n\nAsync callback verification, accepting `fn(err, user)`.\n\n```\nconnect()\n.use(basicAuth(function(user, pass, fn){\n User.authenticate({ user: user, pass: pass }, fn);\n}))\n```\n\n## License\n\nThe MIT License (MIT)\n\nCopyright (c) 2013 Jonathan Ong me@jongleberry.com\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in\nall copies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\nTHE SOFTWARE.",
"readmeFilename": "README.md",
"_id": "basic-auth-connect@1.0.0",
"_from": "basic-auth-connect@1.0.0"
}
test:
@./node_modules/.bin/mocha \
--require should \
--reporter spec
.PHONY: test
\ No newline at end of file
# compression [![Build Status](https://travis-ci.org/expressjs/compression.png)](https://travis-ci.org/expressjs/compression)
Connect's compress middleware as its own module. Works with and without Connect.
```js
var compress = require('compression')()
http.createServer(function (req, res) {
compress(req, res, function (err) {
if (err) throw err
res.end('hello world')
})
})
var app = require('connect')()
app.use(compress)
```
## API
### var middleware = compress([options])
In addition to `zlib` options, additional options are:
- `threshold` <1kb> - only compress the response if the byte size is at or above a threshold
- `filter` - a filter callback function
## License
The MIT License (MIT)
Copyright (c) 2014 Jonathan Ong me@jongleberry.com
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.
\ No newline at end of file
/*!
* Connect - compress
* Copyright(c) 2010 Sencha Inc.
* Copyright(c) 2011 TJ Holowaychuk
* MIT Licensed
*/
/**
* Module dependencies.
*/
var zlib = require('zlib');
var bytes = require('bytes');
var Negotiator = require('negotiator');
var compressible = require('compressible');
/**
* Supported content-encoding methods.
*/
exports.methods = {
gzip: zlib.createGzip
, deflate: zlib.createDeflate
};
/**
* Default filter function.
*/
exports.filter = function(req, res){
return compressible(res.getHeader('Content-Type'));
};
/**
* Compress:
*
* Compress response data with gzip/deflate.
*
* Filter:
*
* A `filter` callback function may be passed to
* replace the default logic of:
*
* exports.filter = function(req, res){
* return /json|text|javascript/.test(res.getHeader('Content-Type'));
* };
*
* Threshold:
*
* Only compress the response if the byte size is at or above a threshold.
* Always compress while streaming.
*
* - `threshold` - string representation of size or bytes as an integer.
*
* Options:
*
* All remaining options are passed to the gzip/deflate
* creation functions. Consult node's docs for additional details.
*
* - `chunkSize` (default: 16*1024)
* - `windowBits`
* - `level`: 0-9 where 0 is no compression, and 9 is slow but best compression
* - `memLevel`: 1-9 low is slower but uses less memory, high is fast but uses more
* - `strategy`: compression strategy
*
* @param {Object} options
* @return {Function}
* @api public
*/
module.exports = function compress(options) {
options = options || {};
var filter = options.filter || exports.filter;
var threshold;
if (false === options.threshold || 0 === options.threshold) {
threshold = 0
} else if ('string' === typeof options.threshold) {
threshold = bytes(options.threshold)
} else {
threshold = options.threshold || 1024
}
return function compress(req, res, next){
var accept = req.headers['accept-encoding']
, writeHead = res.writeHead
, write = res.write
, end = res.end
, compress = true
, stream;
// see #724
req.on('close', function(){
res.write = res.end = function(){};
});
// flush is noop by default
res.flush = noop;
// proxy
res.write = function(chunk, encoding){
if (!this.headerSent) {
// if content-length is set and is lower
// than the threshold, don't compress
var length = res.getHeader('content-length');
if (!isNaN(length) && length < threshold) compress = false;
this._implicitHeader();
}
return stream
? stream.write(new Buffer(chunk, encoding))
: write.call(res, chunk, encoding);
};
res.end = function(chunk, encoding){
if (chunk) {
if (!this.headerSent && getSize(chunk) < threshold) compress = false;
this.write(chunk, encoding);
} else if (!this.headerSent) {
// response size === 0
compress = false;
}
return stream
? stream.end()
: end.call(res);
};
res.writeHead = function(){
// default request filter
if (!filter(req, res)) return writeHead.apply(res, arguments);
// vary
var vary = res.getHeader('Vary');
if (!vary) {
res.setHeader('Vary', 'Accept-Encoding');
} else if (!~vary.indexOf('Accept-Encoding')) {
res.setHeader('Vary', vary + ', Accept-Encoding');
}
if (!compress) return writeHead.apply(res, arguments);
var encoding = res.getHeader('Content-Encoding') || 'identity';
// already encoded
if ('identity' != encoding) return writeHead.apply(res, arguments);
// SHOULD use identity
if (!accept) return writeHead.apply(res, arguments);
// head
if ('HEAD' == req.method) return writeHead.apply(res, arguments);
// compression method
var method = new Negotiator(req).preferredEncoding(['gzip', 'deflate', 'identity']);
// negotiation failed
if (method === 'identity') return writeHead.apply(res, arguments);
// compression stream
stream = exports.methods[method](options);
// overwrite the flush method
res.flush = function(){
stream.flush();
}
// header fields
res.setHeader('Content-Encoding', method);
res.removeHeader('Content-Length');
// compression
stream.on('data', function(chunk){
write.call(res, chunk);
});
stream.on('end', function(){
end.call(res);
});
stream.on('drain', function() {
res.emit('drain');
});
writeHead.apply(res, arguments);
};
next();
};
};
function getSize(chunk) {
return Buffer.isBuffer(chunk)
? chunk.length
: Buffer.byteLength(chunk);
}
function noop(){}
# Compiled source #
###################
*.com
*.class
*.dll
*.exe
*.o
*.so
# Packages #
############
# it's better to unpack these files and commit the raw source
# git has its own built in compression methods
*.7z
*.dmg
*.gz
*.iso
*.jar
*.rar
*.tar
*.zip
# Logs and databases #
######################
*.log
*.sql
*.sqlite
# OS generated files #
######################
.DS_Store*
# Icon?
ehthumbs.db
Thumbs.db
# Node.js #
###########
lib-cov
*.seed
*.log
*.csv
*.dat
*.out
*.pid
*.gz
pids
logs
results
node_modules
npm-debug.log
# Components #
##############
/build
/components
# Sublime Text #
##############
*.sublime-project
*.sublime-workspace
\ No newline at end of file
# Compressible [![Build Status](https://travis-ci.org/expressjs/compressible.png)](https://travis-ci.org/expressjs/compressible)
Compressible `Content-Type` / `mime` checking.
## API
### compressible(type)
```js
var compressible = require('compressible')
compressible('text/html') // -> true
compressible('image/png') // -> false
```
### compressible.get(type)
Returns the specifications object associated with the given `Content-Type`.
Generates an object using the regex if none is found.
### compressible.specs
Exports `specifications.json`.
### compressible.regex
The regular expression that checks the `Content-Type`.
However, you should use `compressible(type)` instead of this regular expression due to additional non-regex checks.
## License
The MIT License (MIT)
Copyright (c) 2013 Jonathan Ong me@jongleberry.com
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.
\ No newline at end of file
var assert = require('assert')
, Benchmark = require('benchmark')
, suite = new Benchmark.Suite
, mime = require('mime')
, keys = Object.keys(mime.types)
, compressible = require('./index.js')
, benchmarks = require('beautify-benchmark')
function getRandomType () {
var type = mime.types[keys[Math.floor(Math.random() * keys.length)]]
return type + mime.charsets.lookup(type)
}
function legacy (type) {
if (!type || typeof type !== "string") return false
var spec = compressible.specs[type.split(';')]
return spec ? spec.compressible : compressible.regex.test(type)
}
function previous (type) {
if (!type || typeof type !== "string") return false
var i = type.indexOf(';')
, spec = compressible.specs[i < 0 ? type : type.slice(0, i)]
return spec ? spec.compressible : compressible.regex.test(type)
}
describe('Compressible performance benchmarks.', function () {
it('Performance of `current` should be within the top 95%', function () {
suite.add('current', function() {
compressible(getRandomType())
})
.add('previous', function () {
previous(getRandomType())
})
.add('legacy', function () {
legacy(getRandomType())
})
.on('cycle', function (event) {
benchmarks.add(event.target)
})
.on('start', function (event) {
console.log('\n Starting...')
})
.on('complete', function done () {
console.log('\n Done!')
var result = benchmarks.getPercent('current')
benchmarks.log()
if (result < 95)
assert.fail('' + result + '%', '95%`', null, '>=', done)
})
.run({ 'async': false })
})
})
\ No newline at end of file
module.exports = compressible
compressible.specs =
compressible.specifications = require('./specifications.json')
compressible.regex =
compressible.regexp = /json|text|javascript|dart|ecmascript|xml/
compressible.get = get
function compressible(type) {
if (!type || typeof type !== "string") return false
var i = type.indexOf(';')
, spec = compressible.specs[~i ? type.slice(0, i) : type]
return spec ? spec.compressible : compressible.regex.test(type)
}
function get(type) {
if (!type || typeof type !== "string") return {
compressible: false,
sources: [],
notes: "Invalid type."
}
var spec = compressible.specs[type.split(';')[0]]
return spec ? spec : {
compressible: compressible.regex.test(type),
sources: ["compressible.regex"],
notes: "Automatically generated via regex."
}
}
\ No newline at end of file
{
"name": "compressible",
"description": "Compressible Content-Type / mime checking",
"version": "1.0.0",
"author": {
"name": "Jonathan Ong",
"email": "me@jongleberry.com",
"url": "http://jongleberry.com"
},
"contributors": {
"name": "Jeremiah Senkpiel",
"email": "fishrock123@rocketmail.com",
"url": "https://searchbeam.jit.su",
"twitter": "https://twitter.com/fishrock123"
},
"license": "MIT",
"repository": {
"type": "git",
"url": "https://github.com/expressjs/compressible.git"
},
"bugs": {
"url": "https://github.com/expressjs/compressible/issues"
},
"keywords": [
"compress",
"gzip",
"mime",
"content-type"
],
"devDependencies": {
"mocha": "*",
"benchmark": "*",
"beautify-benchmark": "~0.2.4",
"mime": "*"
},
"scripts": {
"test": "mocha --reporter spec",
"posttest": "mocha --reporter spec bench.js"
},
"readme": "# Compressible [![Build Status](https://travis-ci.org/expressjs/compressible.png)](https://travis-ci.org/expressjs/compressible)\n\nCompressible `Content-Type` / `mime` checking.\n\n## API\n\n### compressible(type)\n\n```js\nvar compressible = require('compressible')\ncompressible('text/html') // -> true\ncompressible('image/png') // -> false\n```\n\n### compressible.get(type)\n\nReturns the specifications object associated with the given `Content-Type`.\nGenerates an object using the regex if none is found.\n\n### compressible.specs\n\nExports `specifications.json`.\n\n### compressible.regex\n\nThe regular expression that checks the `Content-Type`.\nHowever, you should use `compressible(type)` instead of this regular expression due to additional non-regex checks.\n\n## License\n\nThe MIT License (MIT)\n\nCopyright (c) 2013 Jonathan Ong me@jongleberry.com\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in\nall copies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\nTHE SOFTWARE.",
"readmeFilename": "README.md",
"_id": "compressible@1.0.0",
"_from": "compressible@1.0.0"
}
var assert = require('assert')
var specifications = require('./specifications.json')
var compressible = require('./')
// None of these should be actual types so that the lookup will never include them.
var example_types = [
{ type: 'something/text', should: true },
{ type: 'thingie/dart', should: true },
{ type: 'type/json', should: true },
{ type: 'ecmascript/6', should: true },
{ type: 'data/beans+xml', should: true },
{ type: 'asdf/nope', should: false },
{ type: 'cats', should: false }
]
var invalid_types = [
undefined,
null,
0,
1,
false,
true
]
var object_true = {
compressible: true,
sources: ["compressible.regex"],
notes: "Automatically generated via regex."
}, object_false = {
compressible: false,
sources: ["compressible.regex"],
notes: "Automatically generated via regex."
}
describe('Testing if spec lookups are correct.', function () {
for (var type in specifications) {
var value = specifications[type].compressible
it(type + ' should' + (value ? ' ' : ' not ') + 'be compressible', function () {
assert.equal(compressible(type), value)
})
}
})
describe('Testing if the regex works as intended.', function () {
example_types.forEach(function (example) {
it(example.type + ' should' + (example.should ? ' ' : ' not ') + 'be compressible', function () {
assert.equal(compressible(example.type), example.should)
})
})
})
describe('Testing if getter returns the correct objects.', function () {
it('All spec objects should be get-able', function () {
for (var type in specifications) {
assert.equal(compressible.get(type), specifications[type])
}
})
example_types.forEach(function (example) {
it(example.type + ' should generate a ' + (example.should ? 'true' : 'false') + ' object', function () {
assert.deepEqual(compressible.get(example.type), example.should ? object_true: object_false)
})
})
})
describe('Testing if charsets are handled correctly.', function () {
it('Charsets should be stripped off without issue', function () {
for (var type in specifications) {
var value = specifications[type].compressible
assert.equal(compressible(type + '; charset=utf-8'), value)
}
})
it('Types with charsets should be get-able', function () {
for (var type in specifications) {
assert.equal(compressible.get(type + '; charset=utf-8'), specifications[type])
}
})
})
describe('Ensuring invalid types do not cause errors.', function () {
it('No arguments should return false without error', function () {
assert.equal(compressible(), false)
})
invalid_types.forEach(function (invalid) {
it(invalid + ' should return false without error', function () {
assert.doesNotThrow(function () {
assert.equal(compressible(invalid), false)
})
})
})
})
\ No newline at end of file
{
"name": "compression",
"description": "Compression middleware for connect and node.js",
"version": "1.0.0",
"author": {
"name": "Jonathan Ong",
"email": "me@jongleberry.com",
"url": "http://jongleberry.com"
},
"license": "MIT",
"repository": {
"type": "git",
"url": "https://github.com/expressjs/compression.git"
},
"bugs": {
"url": "https://github.com/expressjs/compression/issues"
},
"dependencies": {
"bytes": "0.2.1",
"negotiator": "0.3.0",
"compressible": "1.0.0"
},
"devDependencies": {
"supertest": "*",
"connect": "*",
"mocha": "*",
"should": "*"
},
"scripts": {
"test": "make test"
},
"readme": "# compression [![Build Status](https://travis-ci.org/expressjs/compression.png)](https://travis-ci.org/expressjs/compression)\n\nConnect's compress middleware as its own module. Works with and without Connect.\n\n```js\nvar compress = require('compression')()\n\nhttp.createServer(function (req, res) {\n compress(req, res, function (err) {\n if (err) throw err\n\n res.end('hello world')\n })\n})\n\nvar app = require('connect')()\napp.use(compress)\n```\n\n## API\n\n### var middleware = compress([options])\n\nIn addition to `zlib` options, additional options are:\n\n- `threshold` <1kb> - only compress the response if the byte size is at or above a threshold\n- `filter` - a filter callback function\n\n## License\n\nThe MIT License (MIT)\n\nCopyright (c) 2014 Jonathan Ong me@jongleberry.com\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in\nall copies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\nTHE SOFTWARE.",
"readmeFilename": "README.md",
"_id": "compression@1.0.0",
"_from": "compression@1.0.0"
}
node_js:
- "0.10"
- "0.11"
language: node_js
\ No newline at end of file
test:
@NODE_ENV=test ./node_modules/.bin/mocha \
--reporter spec \
--require should
.PHONY: test
\ No newline at end of file
# Timeout
Previously `connect.timeout()`.
Usage:
```js
var app = require('connect');
app.use(require('timeout')(300))
```
## API
### fn = timeout(ms)
Returns middleware that times out in `ms` milliseconds.
## License
The MIT License (MIT)
Copyright (c) 2014 Jonathan Ong me@jongleberry.com
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.
/*!
* Connect - timeout
* Ported from https://github.com/LearnBoost/connect-timeout
* MIT Licensed
*/
/**
* Module dependencies.
*/
var debug = require('debug')('connect:timeout');
/**
* Timeout:
*
* Times out the request in `ms`, defaulting to `5000`. The
* method `req.clearTimeout()` is added to revert this behaviour
* programmatically within your application's middleware, routes, etc.
*
* The timeout error is passed to `next()` so that you may customize
* the response behaviour. This error has the `.timeout` property as
* well as `.status == 503`.
*
* @param {Number} ms
* @return {Function}
* @api public
*/
module.exports = function timeout(ms) {
ms = ms || 5000;
return function(req, res, next) {
var id = setTimeout(function(){
req.emit('timeout', ms);
}, ms);
req.on('timeout', function(){
if (res.headersSent) return debug('response started, cannot timeout');
var err = new Error('Response timeout');
err.timeout = ms;
err.status = 503;
next(err);
});
req.clearTimeout = function(){
clearTimeout(id);
};
var writeHead = res.writeHead;
res.writeHead = function(){
clearTimeout(id);
writeHead.apply(res, arguments);
}
next();
};
};
{
"name": "connect-timeout",
"description": "timeout middleware",
"version": "1.0.0",
"author": {
"name": "Jonathan Ong",
"email": "me@jongleberry.com",
"url": "http://jongleberry.com"
},
"license": "MIT",
"repository": {
"type": "git",
"url": "https://github.com/expressjs/timeout.git"
},
"bugs": {
"url": "https://github.com/expressjs/timeout/issues"
},
"dependencies": {
"debug": "*"
},
"devDependencies": {
"mocha": "^1.17.0",
"should": "^3.0.0",
"supertest": "*",
"connect": "*"
},
"scripts": {
"test": "make test"
},
"readme": "# Timeout\n\nPreviously `connect.timeout()`.\n\nUsage:\n\n```js\nvar app = require('connect');\napp.use(require('timeout')(300))\n```\n\n## API\n\n### fn = timeout(ms)\n\nReturns middleware that times out in `ms` milliseconds.\n\n## License\n\nThe MIT License (MIT)\n\nCopyright (c) 2014 Jonathan Ong me@jongleberry.com\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in\nall copies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\nTHE SOFTWARE.\n",
"readmeFilename": "README.md",
"_id": "connect-timeout@1.0.0",
"_from": "connect-timeout@1.0.0"
}
# cookie-parser
Parse _Cookie_ header and populate `req.cookies` with an object keyed by the cookie
names. Optionally you may enabled signed cookie support by passing a `secret` string,
which assigns `req.secret` so it may be used by other middleware.
```js
var cookieParser = require('cookie-parser');
connect()
.use(cookieParser('optional secret string'))
.use(function(req, res, next){
res.end(JSON.stringify(req.cookies));
})
```
## install
```shell
npm install cookie-parser
```
## License
MIT
var cookie = require('cookie');
var parse = require('./lib/parse');
/**
* Parse _Cookie_ header and populate `req.cookies`
* with an object keyed by the cookie names. Optionally
* you may enabled signed cookie support by passing
* a `secret` string, which assigns `req.secret` so
* it may be used by other middleware.
*
* Examples:
*
* connect()
* .use(connect.cookieParser('optional secret string'))
* .use(function(req, res, next){
* res.end(JSON.stringify(req.cookies));
* })
*
* @param {String} secret
* @return {Function}
* @api public
*/
module.exports = function cookieParser(secret, opt){
return function cookieParser(req, res, next) {
if (req.cookies) return next();
var cookies = req.headers.cookie;
req.secret = secret;
req.cookies = {};
req.signedCookies = {};
if (cookies) {
try {
req.cookies = cookie.parse(cookies, opt);
if (secret) {
req.signedCookies = parse.signedCookies(req.cookies, secret);
req.signedCookies = parse.JSONCookies(req.signedCookies);
}
req.cookies = parse.JSONCookies(req.cookies);
} catch (err) {
err.status = 400;
return next(err);
}
}
next();
};
};
var signature = require('cookie-signature');
/**
* Parse signed cookies, returning an object
* containing the decoded key/value pairs,
* while removing the signed key from `obj`.
*
* @param {Object} obj
* @return {Object}
* @api private
*/
exports.signedCookies = function(obj, secret){
var ret = {};
Object.keys(obj).forEach(function(key){
var val = obj[key];
if (0 == val.indexOf('s:')) {
val = signature.unsign(val.slice(2), secret);
if (val) {
ret[key] = val;
delete obj[key];
}
}
});
return ret;
};
/**
* Parse JSON cookies.
*
* @param {Object} obj
* @return {Object}
* @api private
*/
exports.JSONCookies = function(obj){
Object.keys(obj).forEach(function(key){
var val = obj[key];
var res = exports.JSONCookie(val);
if (res) obj[key] = res;
});
return obj;
};
/**
* Parse JSON cookie string
*
* @param {String} str
* @return {Object} Parsed object or null if not json cookie
* @api private
*/
exports.JSONCookie = function(str) {
if (0 == str.indexOf('j:')) {
try {
return JSON.parse(str.slice(2));
} catch (err) {
// no op
}
}
};
// MIT License
Copyright (C) Roman Shtylman <shtylman@gmail.com>
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.
# cookie [![Build Status](https://secure.travis-ci.org/shtylman/node-cookie.png?branch=master)](http://travis-ci.org/shtylman/node-cookie) #
cookie is a basic cookie parser and serializer. It doesn't make assumptions about how you are going to deal with your cookies. It basically just provides a way to read and write the HTTP cookie headers.
See [RFC6265](http://tools.ietf.org/html/rfc6265) for details about the http header for cookies.
## how?
```
npm install cookie
```
```javascript
var cookie = require('cookie');
var hdr = cookie.serialize('foo', 'bar');
// hdr = 'foo=bar';
var cookies = cookie.parse('foo=bar; cat=meow; dog=ruff');
// cookies = { foo: 'bar', cat: 'meow', dog: 'ruff' };
```
## more
The serialize function takes a third parameter, an object, to set cookie options. See the RFC for valid values.
### path
> cookie path
### expires
> absolute expiration date for the cookie (Date object)
### maxAge
> relative max age of the cookie from when the client receives it (seconds)
### domain
> domain for the cookie
### secure
> true or false
### httpOnly
> true or false
/// Serialize the a name value pair into a cookie string suitable for
/// http headers. An optional options object specified cookie parameters
///
/// serialize('foo', 'bar', { httpOnly: true })
/// => "foo=bar; httpOnly"
///
/// @param {String} name
/// @param {String} val
/// @param {Object} options
/// @return {String}
var serialize = function(name, val, opt){
opt = opt || {};
var enc = opt.encode || encode;
var pairs = [name + '=' + enc(val)];
if (opt.maxAge) pairs.push('Max-Age=' + opt.maxAge);
if (opt.domain) pairs.push('Domain=' + opt.domain);
if (opt.path) pairs.push('Path=' + opt.path);
if (opt.expires) pairs.push('Expires=' + opt.expires.toUTCString());
if (opt.httpOnly) pairs.push('HttpOnly');
if (opt.secure) pairs.push('Secure');
return pairs.join('; ');
};
/// Parse the given cookie header string into an object
/// The object has the various cookies as keys(names) => values
/// @param {String} str
/// @return {Object}
var parse = function(str, opt) {
opt = opt || {};
var obj = {}
var pairs = str.split(/[;,] */);
var dec = opt.decode || decode;
pairs.forEach(function(pair) {
var eq_idx = pair.indexOf('=')
// skip things that don't look like key=value
if (eq_idx < 0) {
return;
}
var key = pair.substr(0, eq_idx).trim()
var val = pair.substr(++eq_idx, pair.length).trim();
// quoted values
if ('"' == val[0]) {
val = val.slice(1, -1);
}
// only assign once
if (undefined == obj[key]) {
try {
obj[key] = dec(val);
} catch (e) {
obj[key] = val;
}
}
});
return obj;
};
var encode = encodeURIComponent;
var decode = decodeURIComponent;
module.exports.serialize = serialize;
module.exports.parse = parse;
{
"author": {
"name": "Roman Shtylman",
"email": "shtylman@gmail.com"
},
"name": "cookie",
"description": "cookie parsing and serialization",
"version": "0.1.0",
"repository": {
"type": "git",
"url": "git://github.com/shtylman/node-cookie.git"
},
"keywords": [
"cookie",
"cookies"
],
"main": "index.js",
"scripts": {
"test": "mocha"
},
"dependencies": {},
"devDependencies": {
"mocha": "1.x.x"
},
"optionalDependencies": {},
"engines": {
"node": "*"
},
"readme": "# cookie [![Build Status](https://secure.travis-ci.org/shtylman/node-cookie.png?branch=master)](http://travis-ci.org/shtylman/node-cookie) #\n\ncookie is a basic cookie parser and serializer. It doesn't make assumptions about how you are going to deal with your cookies. It basically just provides a way to read and write the HTTP cookie headers.\n\nSee [RFC6265](http://tools.ietf.org/html/rfc6265) for details about the http header for cookies.\n\n## how?\n\n```\nnpm install cookie\n```\n\n```javascript\nvar cookie = require('cookie');\n\nvar hdr = cookie.serialize('foo', 'bar');\n// hdr = 'foo=bar';\n\nvar cookies = cookie.parse('foo=bar; cat=meow; dog=ruff');\n// cookies = { foo: 'bar', cat: 'meow', dog: 'ruff' };\n```\n\n## more\n\nThe serialize function takes a third parameter, an object, to set cookie options. See the RFC for valid values.\n\n### path\n> cookie path\n\n### expires\n> absolute expiration date for the cookie (Date object)\n\n### maxAge\n> relative max age of the cookie from when the client receives it (seconds)\n\n### domain\n> domain for the cookie\n\n### secure\n> true or false\n\n### httpOnly\n> true or false\n\n",
"readmeFilename": "README.md",
"bugs": {
"url": "https://github.com/shtylman/node-cookie/issues"
},
"_id": "cookie@0.1.0",
"_from": "cookie@0.1.0"
}
var assert = require('assert');
var cookie = require('..');
suite('parse');
test('basic', function() {
assert.deepEqual({ foo: 'bar' }, cookie.parse('foo=bar'));
assert.deepEqual({ foo: '123' }, cookie.parse('foo=123'));
});
test('ignore spaces', function() {
assert.deepEqual({ FOO: 'bar', baz: 'raz' },
cookie.parse('FOO = bar; baz = raz'));
});
test('escaping', function() {
assert.deepEqual({ foo: 'bar=123456789&name=Magic+Mouse' },
cookie.parse('foo="bar=123456789&name=Magic+Mouse"'));
assert.deepEqual({ email: ' ",;/' },
cookie.parse('email=%20%22%2c%3b%2f'));
});
test('ignore escaping error and return original value', function() {
assert.deepEqual({ foo: '%1', bar: 'bar' }, cookie.parse('foo=%1;bar=bar'));
});
test('ignore non values', function() {
assert.deepEqual({ foo: '%1', bar: 'bar' }, cookie.parse('foo=%1;bar=bar;HttpOnly;Secure'));
});
test('unencoded', function() {
assert.deepEqual({ foo: 'bar=123456789&name=Magic+Mouse' },
cookie.parse('foo="bar=123456789&name=Magic+Mouse"',{
decode: function(value) { return value; }
}));
assert.deepEqual({ email: '%20%22%2c%3b%2f' },
cookie.parse('email=%20%22%2c%3b%2f',{
decode: function(value) { return value; }
}));
})
// builtin
var assert = require('assert');
var cookie = require('..');
suite('serialize');
test('basic', function() {
assert.equal('foo=bar', cookie.serialize('foo', 'bar'));
assert.equal('foo=bar%20baz', cookie.serialize('foo', 'bar baz'));
});
test('path', function() {
assert.equal('foo=bar; Path=/', cookie.serialize('foo', 'bar', {
path: '/'
}));
});
test('secure', function() {
assert.equal('foo=bar; Secure', cookie.serialize('foo', 'bar', {
secure: true
}));
assert.equal('foo=bar', cookie.serialize('foo', 'bar', {
secure: false
}));
});
test('domain', function() {
assert.equal('foo=bar; Domain=example.com', cookie.serialize('foo', 'bar', {
domain: 'example.com'
}));
});
test('httpOnly', function() {
assert.equal('foo=bar; HttpOnly', cookie.serialize('foo', 'bar', {
httpOnly: true
}));
});
test('maxAge', function() {
assert.equal('foo=bar; Max-Age=1000', cookie.serialize('foo', 'bar', {
maxAge: 1000
}));
});
test('escaping', function() {
assert.deepEqual('cat=%2B%20', cookie.serialize('cat', '+ '));
});
test('parse->serialize', function() {
assert.deepEqual({ cat: 'foo=123&name=baz five' }, cookie.parse(
cookie.serialize('cat', 'foo=123&name=baz five')));
assert.deepEqual({ cat: ' ";/' }, cookie.parse(
cookie.serialize('cat', ' ";/')));
});
test('unencoded', function() {
assert.deepEqual('cat=+ ', cookie.serialize('cat', '+ ', {
encode: function(value) { return value; }
}));
})
{
"name": "cookie-parser",
"version": "1.0.1",
"description": "cookie parsing with signatures",
"keywords": [
"cookie",
"middleware"
],
"repository": {
"type": "git",
"url": "git://github.com/expressjs/cookie-parser.git"
},
"author": {
"name": "TJ Holowaychuk",
"email": "tj@vision-media.ca",
"url": "http://tjholowaychuk.com"
},
"dependencies": {
"cookie": "0.1.0",
"cookie-signature": "1.0.3"
},
"devDependencies": {
"mocha": "~1.17.0",
"connect": "2.13.0",
"supertest": "0.9.0"
},
"licenses": "MIT",
"main": "./index.js",
"engines": {
"node": ">= 0.10.0"
},
"scripts": {
"test": "mocha --ui bdd --reporter list -- test/*.js"
},
"readme": "# cookie-parser\n\nParse _Cookie_ header and populate `req.cookies` with an object keyed by the cookie\nnames. Optionally you may enabled signed cookie support by passing a `secret` string,\nwhich assigns `req.secret` so it may be used by other middleware.\n\n```js\nvar cookieParser = require('cookie-parser');\n\nconnect()\n .use(cookieParser('optional secret string'))\n .use(function(req, res, next){\n res.end(JSON.stringify(req.cookies));\n })\n```\n\n## install\n\n```shell\nnpm install cookie-parser\n```\n\n## License\n\nMIT\n",
"readmeFilename": "README.md",
"bugs": {
"url": "https://github.com/expressjs/cookie-parser/issues"
},
"_id": "cookie-parser@1.0.1",
"_from": "cookie-parser@1.0.1"
}
var connect = require('connect')
, request = require('supertest')
, signature = require('cookie-signature');
var app = connect();
app.use(connect.cookieParser('keyboard cat'));
app.use(function(req, res, next){
if ('/signed' != req.url) return next();
res.end(JSON.stringify(req.signedCookies));
});
app.use(function(req, res, next){
res.end(JSON.stringify(req.cookies));
});
describe('connect.cookieParser()', function(){
describe('when no cookies are sent', function(){
it('should default req.cookies to {}', function(done){
request(app)
.get('/')
.expect('{}', done);
})
it('should default req.signedCookies to {}', function(done){
request(app)
.get('/signed')
.expect('{}', done);
})
})
describe('when cookies are sent', function(){
it('should populate req.cookies', function(done){
request(app)
.get('/')
.set('Cookie', 'foo=bar; bar=baz')
.expect('{"foo":"bar","bar":"baz"}', done);
})
})
describe('when a secret is given', function(){
var val = signature.sign('foobarbaz', 'keyboard cat');
// TODO: "bar" fails...
it('should populate req.signedCookies', function(done){
request(app)
.get('/signed')
.set('Cookie', 'foo=s:' + val)
.expect('{"foo":"foobarbaz"}', done);
})
it('should remove the signed value from req.cookies', function(done){
request(app)
.get('/')
.set('Cookie', 'foo=s:' + val)
.expect('{}', done);
})
it('should omit invalid signatures', function(done){
request(app)
.get('/signed')
.set('Cookie', 'foo=' + val + '3')
.expect('{}', function(){
request(app)
.get('/')
.set('Cookie', 'foo=' + val + '3')
.expect('{"foo":"foobarbaz.CP7AWaXDfAKIRfH49dQzKJx7sKzzSoPq7/AcBBRVwlI3"}', done);
});
})
})
})
node_js:
- "0.10"
- "0.11"
language: node_js
\ No newline at end of file
test:
@NODE_ENV=test ./node_modules/.bin/mocha \
--reporter spec \
--require should
.PHONY: test
\ No newline at end of file
/*!
* Connect - csrf
* Copyright(c) 2011 Sencha Inc.
* MIT Licensed
*/
/**
* Module dependencies.
*/
var uid = require('uid2');
var crypto = require('crypto');
/**
* Anti CSRF:
*
* CSRF protection middleware.
*
* This middleware adds a `req.csrfToken()` function to make a token
* 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 session.
*
* The default `value` function checks `req.body` generated
* by the `bodyParser()` middleware, `req.query` generated
* by `query()`, and the "X-CSRF-Token" header field.
*
* This middleware requires session support, thus should be added
* somewhere _below_ `session()` and `cookieParser()`.
*
* Options:
*
* - `value` a function accepting the request, returning the token
*
* @param {Object} options
* @api public
*/
module.exports = function csrf(options) {
options = options || {};
var value = options.value || defaultValue;
return function(req, res, next){
// already have one
var secret = req.session.csrfSecret;
if (secret) return createToken(secret);
// generate secret
uid(24, function(err, secret){
if (err) return next(err);
req.session.csrfSecret = secret;
createToken(secret);
});
// generate the token
function createToken(secret) {
var token;
// lazy-load token
req.csrfToken = function csrfToken() {
return token || (token = saltedToken(secret));
};
// ignore these methods
if ('GET' == req.method || 'HEAD' == req.method || 'OPTIONS' == req.method) return next();
// determine user-submitted value
var val = value(req);
// check
if (!checkToken(val, secret)) {
var err = new Error('invalid csrf token');
err.status = 403;
next(err);
return;
}
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'])
|| (req.headers['x-xsrf-token']);
}
/**
* Return salted token.
*
* @param {String} secret
* @return {String}
* @api private
*/
function saltedToken(secret) {
return createToken(generateSalt(10), secret);
}
/**
* Creates a CSRF token from a given salt and secret.
*
* @param {String} salt (should be 10 characters)
* @param {String} secret
* @return {String}
* @api private
*/
function createToken(salt, secret) {
return salt + crypto
.createHash('sha1')
.update(salt + secret)
.digest('base64');
}
/**
* Checks if a given CSRF token matches the given secret.
*
* @param {String} token
* @param {String} secret
* @return {Boolean}
* @api private
*/
function checkToken(token, secret) {
if ('string' != typeof token) return false;
return token === createToken(token.slice(0, 10), secret);
}
/**
* Generates a random salt, using a fast non-blocking PRNG (Math.random()).
*
* @param {Number} length
* @return {String}
* @api private
*/
function generateSalt(length) {
var i, r = [];
for (i = 0; i < length; ++i) {
r.push(SALTCHARS[Math.floor(Math.random() * SALTCHARS.length)]);
}
return r.join('');
}
var SALTCHARS = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789';
...@@ -8,5 +8,5 @@ ...@@ -8,5 +8,5 @@
"dependencies": {}, "dependencies": {},
"readme": "ERROR: No README data found!", "readme": "ERROR: No README data found!",
"_id": "uid2@0.0.3", "_id": "uid2@0.0.3",
"_from": "uid2@0.0.3" "_from": "uid2@~0.0.2"
} }
{
"name": "csurf",
"description": "CSRF token middleware",
"version": "1.0.0",
"author": {
"name": "Jonathan Ong",
"email": "me@jongleberry.com",
"url": "http://jongleberry.com"
},
"license": "MIT",
"repository": {
"type": "git",
"url": "https://github.com/expressjs/csurf.git"
},
"bugs": {
"url": "https://github.com/expressjs/csurf/issues"
},
"dependencies": {
"uid2": "~0.0.2"
},
"devDependencies": {
"cookie-session": "*",
"body-parser": "*",
"mocha": "^1.17.0",
"should": "^3.0.0",
"supertest": "*",
"connect": "*"
},
"scripts": {
"test": "make test"
},
"readme": "ERROR: No README data found!",
"_id": "csurf@1.0.0",
"_from": "csurf@1.0.0"
}
node_js:
- "0.10"
- "0.11"
language: node_js
\ No newline at end of file
test:
@NODE_ENV=test ./node_modules/.bin/mocha \
--reporter spec \
--require should
.PHONY: test
\ No newline at end of file
# Error Handler
Previously `connect.errorHandler()`.
Usage:
```js
var app = require('connect');
app.use(require('errorhandler')())
```
## License
The MIT License (MIT)
Copyright (c) 2014 Jonathan Ong me@jongleberry.com
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.
/*!
* Connect - errorHandler
* Copyright(c) 2010 Sencha Inc.
* Copyright(c) 2011 TJ Holowaychuk
* MIT Licensed
*/
/**
* Module dependencies.
*/
var fs;
try {
fs = require('graceful-fs');
} catch (_) {
fs = require('fs');
}
// environment
var env = process.env.NODE_ENV || 'development';
/**
* Error handler:
*
* Development error handler, providing stack traces
* and error message responses for requests accepting text, html,
* or json.
*
* Text:
*
* By default, and when _text/plain_ is accepted a simple stack trace
* or error message will be returned.
*
* JSON:
*
* When _application/json_ is accepted, connect will respond with
* an object in the form of `{ "error": error }`.
*
* HTML:
*
* When accepted connect will output a nice html stack trace.
*
* @return {Function}
* @api public
*/
exports = module.exports = function errorHandler(){
return function errorHandler(err, req, res, next){
if (err.status) res.statusCode = err.status;
if (res.statusCode < 400) res.statusCode = 500;
if ('test' != env) console.error(err.stack);
var accept = req.headers.accept || '';
// html
if (~accept.indexOf('html')) {
fs.readFile(__dirname + '/public/style.css', 'utf8', function(e, style){
fs.readFile(__dirname + '/public/error.html', 'utf8', function(e, html){
var stack = (err.stack || '')
.split('\n').slice(1)
.map(function(v){ return '<li>' + v + '</li>'; }).join('');
html = html
.replace('{style}', style)
.replace('{stack}', stack)
.replace('{title}', exports.title)
.replace('{statusCode}', res.statusCode)
.replace(/\{error\}/g, escapeHTML(err.toString().replace(/\n/g, '<br/>')));
res.setHeader('Content-Type', 'text/html; charset=utf-8');
res.end(html);
});
});
// json
} else if (~accept.indexOf('json')) {
var error = { message: err.message, stack: err.stack };
for (var prop in err) error[prop] = err[prop];
var json = JSON.stringify({ error: error });
res.setHeader('Content-Type', 'application/json');
res.end(json);
// plain text
} else {
res.setHeader('Content-Type', 'text/plain');
res.end(err.stack);
}
};
};
/**
* Template title, framework authors may override this value.
*/
exports.title = 'Connect';
/**
* Escape the given string of `html`.
*
* @param {String} html
* @return {String}
* @api private
*/
function escapeHTML(html){
return String(html)
.replace(/&(?!\w+;)/g, '&amp;')
.replace(/</g, '&lt;')
.replace(/>/g, '&gt;')
.replace(/"/g, '&quot;');
};
\ No newline at end of file
{
"name": "errorhandler",
"description": "connect's default error handler page",
"version": "1.0.0",
"author": {
"name": "Jonathan Ong",
"email": "me@jongleberry.com",
"url": "http://jongleberry.com"
},
"license": "MIT",
"repository": {
"type": "git",
"url": "https://github.com/expressjs/errorhandler.git"
},
"bugs": {
"url": "https://github.com/expressjs/errorhandler/issues"
},
"devDependencies": {
"mocha": "^1.17.0",
"should": "^3.0.0",
"supertest": "*",
"connect": "*"
},
"scripts": {
"test": "make test"
},
"readme": "# Error Handler\n\nPreviously `connect.errorHandler()`.\n\nUsage:\n\n```js\nvar app = require('connect');\napp.use(require('errorhandler')())\n```\n\n## License\n\nThe MIT License (MIT)\n\nCopyright (c) 2014 Jonathan Ong me@jongleberry.com\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in\nall copies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\nTHE SOFTWARE.\n",
"readmeFilename": "README.md",
"_id": "errorhandler@1.0.0",
"_from": "errorhandler@1.0.0"
}
# express-session
Setup session store with the given `options`.
Session data is _not_ saved in the cookie itself, however
cookies are used, so we must use the [cookieParser()](cookieParser.html)
middleware _before_ `session()`.
## Example
```js
app.use(connect.cookieParser())
app.use(connect.session({ secret: 'keyboard cat', key: 'sid', cookie: { secure: true }}))
```
**Options**
- `key` cookie name defaulting to `connect.sid`
- `store` session store instance
- `secret` session cookie is signed with this secret to prevent tampering
- `cookie` session cookie settings, defaulting to `{ path: '/', httpOnly: true, maxAge: null }`
- `proxy` trust the reverse proxy when setting secure cookies (via "x-forwarded-proto")
**Cookie options**
By default `cookie.maxAge` is `null`, meaning no "expires" parameter is set
so the cookie becomes a browser-session cookie. When the user closes the
browser the cookie (and session) will be removed.
## req.session
To store or access session data, simply use the request property `req.session`,
which is (generally) serialized as JSON by the store, so nested objects
are typically fine. For example below is a user-specific view counter:
```js
app.use(cookieParser())
app.use(session({ secret: 'keyboard cat', cookie: { maxAge: 60000 }}))
app.use(function(req, res, next){
var sess = req.session;
if (sess.views) {
res.setHeader('Content-Type', 'text/html');
res.write('<p>views: ' + sess.views + '</p>');
res.write('<p>expires in: ' + (sess.cookie.maxAge / 1000) + 's</p>');
res.end();
sess.views++;
} else {
sess.views = 1;
res.end('welcome to the session demo. refresh!');
}
})
```
## Session#regenerate()
To regenerate the session simply invoke the method, once complete
a new SID and `Session` instance will be initialized at `req.session`.
```js
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.
```js
req.session.destroy(function(err){
// cannot access session here
});
```
## Session#reload()
Reloads the session data.
```js
req.session.reload(function(err){
// session updated
});
```
## Session#save()
Save the session.
```js
req.session.save(function(err){
// session saved
});
```
## Session#touch()
Updates the `.maxAge` property. Typically this is
not necessary to call, as the session middleware does this for you.
## Session#cookie
Each session has a unique cookie object accompany it. This allows
you to alter the session cookie per visitor. For example we can
set `req.session.cookie.expires` to `false` to enable the cookie
to remain for only the duration of the user-agent.
## Session#maxAge
Alternatively `req.session.cookie.maxAge` will return the time
remaining in milliseconds, which we may also re-assign a new value
to adjust the `.expires` property appropriately. The following
are essentially equivalent
```js
var hour = 3600000;
req.session.cookie.expires = new Date(Date.now() + hour);
req.session.cookie.maxAge = hour;
```
For example when `maxAge` is set to `60000` (one minute), and 30 seconds
has elapsed it will return `30000` until the current request has completed,
at which time `req.session.touch()` is called to reset `req.session.maxAge`
to its original value.
```js
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)`
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment