ConnectHigh performance middleware for node. | |
| lib/connect/middleware/bodyDecoder.js |
Module dependencies.
|
var queryString = require('querystring');
|
Decode request bodies.
return: Function api: public
|
exports = module.exports = function bodyDecoder(){
return function bodyDecoder(req, res, next) {
var decoder = exports.decode[mime(req)];
if (decoder && !req.body) {
var data = '';
req.setEncoding('utf8');
req.addListener('data', function(chunk) { data += chunk; });
req.addListener('end', function() {
req.rawBody = data;
try {
req.body = data
? decoder(data)
: {};
} catch (err) {
return next(err);
}
next();
});
} else {
next();
}
}
};
|
Supported decoders.
- application/x-www-form-urlencoded
- application/json
|
exports.decode = {
'application/x-www-form-urlencoded': queryString.parse,
'application/json': JSON.parse
};
|
| lib/connect/middleware/cache.js |
Module dependencies.
|
var Buffer = require('buffer').Buffer;
|
Cache in memory for the given cacheDuration .
|
module.exports = function cache(cacheDuration){
var cache = {},
queue = {};
return function cache(req, res, next) {
if (req.method !== "GET") {
next();
return;
}
var key = req.headers["accept-encoding"] + req.url,
writeHead = res.writeHead,
write = res.write,
end = res.end,
code,
headers,
chunks = [],
totalSize = 0;
function serve() {
var resp = cache[key];
var headers = resp.headers;
headers["Content-Length"] = resp.body.length;
if (!resp.body.length) resp.body = undefined;
if (localQueue) {
for (var i = 0, l = localQueue.length; i < l; i++) {
var localRes = localQueue[i];
localRes.writeHead(resp.code, headers);
localRes.end(resp.body);
}
delete queue[key];
} else {
res.writeHead(resp.code, headers);
res.end(resp.body);
}
}
if (cache[key]) {
serve();
return;
}
var localQueue = queue[key];
if (localQueue) {
localQueue[localQueue.length] = res;
return;
}
localQueue = queue[key] = [res];
res.writeHead = function (setCode, setHeaders) {
code = setCode;
headers = setHeaders;
};
res.write = function (chunk, encoding) {
if (typeof chunk === 'string') {
var length;
if (!encoding || encoding === 'utf8') {
length = Buffer.byteLength(chunk);
}
var buffer = new Buffer(length);
buffer.write(chunk, encoding);
chunks.push(buffer);
} else {
chunks.push(chunk);
}
totalSize += chunk.length;
};
res.end = function (chunk, encoding) {
if (chunk && chunk.length) {
res.write(chunk, encoding);
}
var body = new Buffer(totalSize);
var offset = 0;
chunks.forEach(function (chunk) {
chunk.copy(body, offset);
offset += chunk.length;
});
cache[key] = {
body: body,
code: code,
headers: headers
};
res.writeHead = writeHead;
res.write = write;
res.end = end;
serve();
if (cacheDuration) {
setTimeout(function(){
delete cache[key];
}, cacheDuration);
} else {
delete cache[key];
}
};
next();
};
};
|
| lib/connect/middleware/cacheManifest.js |
Module dependencies.
|
var fs = require('fs'),
Utils = require('../utils'),
Url = require('url'),
Path = require('path');
|
Generate cache manifest for the given root , networks ,
and fallbacks .
param: String root param: Array networks param: Array fallbacks return: Function api: public
|
module.exports = function cacheManifest(root, networks, fallbacks) {
root = root || process.cwd();
var suffix = "";
if (networks) {
suffix += "\n\nNETWORK:\n" + networks.join("\n");
}
if (fallbacks) {
suffix += "\n\nFALLBACK:\n" +
fallbacks.map(function (second, first) {
return first + " " + second;
}).join("\n");
}
return function cacheManifest(req, res, next) {
if (Url.parse(req.url).pathname === "/cache.manifest") {
Utils.find(root, (/./), function (err, files) {
var latestMtime = 0;
files = files.map(function (entry) {
if (entry.mtime > latestMtime) {
latestMtime = entry.mtime;
}
return entry.path.substr(1);
});
var manifest = "CACHE MANIFEST\n"
+ "# " + latestMtime.toUTCString() + "\n"
+ files.join("\n")
+ suffix;
res.writeHead(200, {
"Content-Type": "text/cache-manifest",
"Last-Modified": latestMtime.toUTCString(),
"Content-Length": manifest.length
});
res.end(manifest);
});
return;
}
next();
};
};
|
| lib/connect/middleware/compiler.js |
Module dependencies.
|
var fs = require('fs'),
path = require('path'),
url = require('url');
|
Require cache.
|
var cache = {};
|
Setup compiler.
Options
src Source directory, defaults to CWD.dest Destination directory, defaults src .enable Array of enabled compilers.
Compilers
sass Compiles cass to cssless Compiles less to csscoffeescript Compiles coffee to js
param: Object options api: public
|
exports = module.exports = function compiler(options){
options = options || {};
var srcDir = process.connectEnv.compilerSrc || options.src || process.cwd(),
destDir = process.connectEnv.compilerDest || options.dest || srcDir,
enable = options.enable;
if (!enable || enable.length === 0) {
throw new Error(s "enable" option is not set, nothing will be compiled.');
}
return function compiler(req, res, next){
if (req.method !== 'GET') return next();
var pathname = url.parse(req.url).pathname;
for (var i = 0, len = enable.length; i < len; ++i) {
var name = enable[i],
compiler = compilers[name];
if (compiler.match.test(pathname)) {
var src = (srcDir + pathname).replace(compiler.match, compiler.ext),
dest = destDir + pathname;
fs.stat(src, function(err, srcStats){
if (err) {
if (err.errno === process.ENOENT) {
next();
} else {
next(err);
}
} else {
fs.stat(dest, function(err, destStats){
if (err) {
if (err.errno === process.ENOENT) {
compile();
} else {
next(err);
}
} else {
if (srcStats.mtime > destStats.mtime) {
compile();
} else {
next();
}
}
});
}
});
function compile() {
fs.readFile(src, 'utf8', function(err, str){
if (err) {
next(err);
} else {
compiler.compile(str, function(err, str){
if (err) {
next(err);
} else {
fs.writeFile(dest, str, 'utf8', function(err){
next(err);
});
}
});
}
});
}
return;
}
}
next();
};
};
|
Bundled compilers:
|
var compilers = exports.compilers = {
sass: {
match: /\.css$/,
ext: '.sass',
compile: function(str, fn){
var sass = cache.sass || (cache.sass = require('sass'));
try {
fn(null, sass.render(str));
} catch (err) {
fn(err);
}
}
},
less: {
match: /\.css$/,
ext: '.less',
compile: function(str, fn){
var less = cache.less || (cache.less = require('less'));
try {
less.render(str, fn);
} catch (err) {
fn(err);
}
}
},
coffeescript: {
match: /\.js$/,
ext: '.coffee',
compile: function(str, fn){
var coffee = cache.coffee || (cache.coffee = require('coffee-script'));
try {
fn(null, coffee.compile(str));
} catch (err) {
fn(err);
}
}
}
};
|
| lib/connect/middleware/conditionalGet.js |
Conditional GET request support.
return: Function api: public
|
module.exports = function conditionalGet(){
return function conditionalGet(req, res, next) {
if (!(req.method === "GET" &&
(req.headers["if-modified-since"] || req.headers["if-none-match"])
)) {
next();
return;
}
var since = req.headers["if-modified-since"],
oldEtag = req.headers["if-none-match"],
writeHead = res.writeHead,
write = res.write,
end = res.end;
since = since && Date.parse(since).valueOf();
res.writeHead = function (code, headers) {
var lastModified = headers["Last-Modified"],
etag = headers["ETag"];
lastModified = lastModified && Date.parse(lastModified).valueOf();
if (!(code === 200 &&
((since && lastModified === since) || (etag && oldEtag === etag))
)) {
res.writeHead = writeHead;
res.writeHead(code, headers);
return;
}
res.write = function () {};
res.end = function () {
res.writeHead = writeHead;
res.write = write;
res.end = end;
var newHeaders = {};
Object.keys(headers).forEach(function (key) {
if (key.indexOf("Content") < 0) {
newHeaders[key] = headers[key];
}
});
res.writeHead(304, newHeaders);
res.end();
};
};
next();
};
};
|
| lib/connect/middleware/cookieDecoder.js |
Module dependencies.
|
var utils = require('./../utils');
|
Parse Cookie header and populate req.cookies .
return: Function api: public
|
module.exports = function cookieDecoder(){
return function cookieDecoder(req, res, next) {
var cookie = req.headers.cookie;
req.cookies = {};
if (cookie) {
try {
req.cookies = utils.parseCookie(cookie);
delete req.headers.cookie;
} catch (err) {
}
next();
} else {
next();
}
};
};
|
| lib/connect/middleware/errorHandler.js |
Module dependencies.
|
var utils = require('./../utils'),
sys = require('sys'),
url = require('url'),
fs = require('fs');
|
Setup error handler with the given options .
Options
showStack respond with both the error message and stack trace. Defaults to false showMessage respond with the exception message only. Defaults to false dumpExceptions dump exceptions to stderr (without terminating the process). Defaults to false
param: Object options return: Function api: public
|
module.exports = function errorHandler(options){
options = options || {};
var showStack = options.showStack,
showMessage = options.showMessage,
dumpExceptions = options.dumpExceptions,
formatUrl = options.formatUrl;
if (process.connectEnv.showErrorStack !== undefined) {
showStack = utils.toBoolean(process.connectEnv.showErrorStack);
}
if (process.connectEnv.showErrorMessage !== undefined) {
showMessage = utils.toBoolean(process.connectEnv.showErrorMessage);
}
if (process.connectEnv.dumpExceptions !== undefined) {
dumpExceptions = utils.toBoolean(process.connectEnv.dumpExceptions);
}
var formatLine = function(v){ return '<li>' + v + '</li>'; };
if (formatUrl) {
var parts, re = /(\/[^\(\)]+):(\d+):(\d+)/;
var formatters = {
'file': function(parts) { return {'protocol':'file', 'hostname':''+parts[1]}; },
'txmt': function(parts) { return {
'protocol':'txmt', 'hostname':'//open',
'query':{'url':'file://'+parts[1],'line':parts[2],'column':parts[3]}};
}
};
formatLine = function(v) {
parts = v.match(re);
if (parts) v = v.replace(parts[0],'<a href="'+url.format( formatters[formatUrl](parts) )+'">'+parts[0]+'</a>');
return '<li>' + v + '</li>';
};
}
return function errorHandler(err, req, res, next){
if (dumpExceptions) {
sys.error(err.stack);
}
if (showStack) {
var accept = req.headers.accept || '';
if (accept.indexOf('html') !== -1) {
fs.readFile(__dirname + '/../public/style.css', function(e, style){
style = style.toString('ascii');
fs.readFile(__dirname + '/../public/error.html', function(e, html){
var stack = err.stack
.split('\n').slice(1)
.map(formatLine).join('');
html = html
.toString('utf8')
.replace('{style}', style)
.replace('{stack}', stack)
.replace(/\{error\}/g, err.toString());
res.writeHead(500, { 'Content-Type': 'text/html' });
res.end(html);
});
});
} else if (accept.indexOf('json') !== -1) {
var json = JSON.stringify({ error: err });
res.writeHead(500, { 'Content-Type': 'application/json' });
res.end(json);
} else {
res.writeHead(500, { 'Content-Type': 'text/plain' });
res.end(err.stack);
}
} else {
var body = showMessage
? err.toString()
: 'Internal Server Error';
res.writeHead(500, { 'Content-Type': 'text/plain' });
res.end(body);
}
};
};
|
| lib/connect/middleware/favicon.js |
Module dependencies.
|
var fs = require('fs'),
utils = require('../utils');
|
Favicon cache.
|
var icon;
|
By default serves the connect favicon, or the favicon
located by the given path.
Examples
connect.createServer(
connect.favicon()
);
connect.createServer(
connect.favicon(__dirname + '/public/favicon.ico')
);
param: String path return: Function api: public
|
module.exports = function favicon(path){
path = path || __dirname + '/../public/favicon.ico';
return function favicon(req, res, next){
if (req.url === '/favicon.ico') {
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=3600'
},
body: buf
}
res.writeHead(200, icon.headers);
res.end(icon.body);
});
}
} else {
next();
}
};
};
|
| lib/connect/middleware/gzip-compress.js |
Module dependencies.
|
var compress = require('compress');
|
Provides gzip compression via the node-compress library.
return: Function api: public
|
module.exports = function gzip(){
return function gzip(req, res, next) {
var writeHead = res.writeHead,
write = res.write,
end = res.end;
res.writeHead = function (code, headers) {
var type = headers["Content-Type"],
accept = req.headers["accept-encoding"];
if (!(code === 200 && accept && accept.indexOf('gzip') >= 0
&& type && (/(text|javascript|json)/).test(type)
&& headers["Content-Encoding"] === undefined)) {
res.writeHead = writeHead;
res.writeHead(code, headers);
return;
}
headers["Content-Encoding"] = "gzip";
delete headers["Content-Length"];
var gzip = new compress.GzipStream();
res.write = function (chunk, encoding) {
gzip.setInputEncoding(encoding);
gzip.write(chunk);
};
res.end = function (chunk, encoding) {
if (chunk) {
res.write(chunk, encoding);
}
gzip.close();
};
gzip.addListener('data', function (chunk) {
write.call(res, chunk);
});
gzip.addListener('error', function(err) {
res.write = write;
res.end = end;
next(err);
});
gzip.addListener('end', function (code) {
res.write = write;
res.end = end;
res.end();
});
res.writeHead = writeHead;
res.writeHead(code, headers);
};
next();
};
};
|
| lib/connect/middleware/gzip-proc.js |
Module dependencies.
|
var child_process = require('child_process'),
sys = require('sys');
|
Provides gzip compression via the gzip executable.
return: Function api: public
|
module.exports = function gzip(){
return function gzip(req, res, next) {
var writeHead = res.writeHead,
write = res.write,
end = res.end;
res.writeHead = function (code, headers) {
var type = headers["Content-Type"],
accept = req.headers["accept-encoding"];
if (!(code === 200 && accept && accept.indexOf('gzip') >= 0
&& type && (/(text|javascript|json)/).test(type)
&& headers["Content-Encoding"] === undefined)) {
res.writeHead = writeHead;
res.writeHead(code, headers);
return;
}
headers["Content-Encoding"] = "gzip";
delete headers["Content-Length"];
var gzip = child_process.spawn("gzip", ["-9"]);
res.write = function (chunk, encoding) {
gzip.stdin.write(chunk, encoding);
};
res.end = function (chunk, encoding) {
if (chunk) {
res.write(chunk, encoding);
}
gzip.stdin.end();
};
gzip.stdout.addListener('data', function (chunk) {
write.call(res, chunk);
});
gzip.addListener("exit", function (code) {
res.write = write;
res.end = end;
res.end();
});
res.writeHead = writeHead;
res.writeHead(code, headers);
};
next();
};
};
|
| lib/connect/middleware/gzip.js |
try {
module.exports = require('./gzip-compress');
} catch (e) {
if (/^Cannot find module /.test(e.message))
module.exports = require('./gzip-proc');
else
throw e;
}
|
|
| lib/connect/middleware/lint.js |
Module dependencies.
|
var connect = require('./../index'),
sys = require('sys');
|
Setup lint for the given server .
return: Function api: public
|
module.exports = function lint(server){
if (!server) {
throw new Error('lint "server" must be passed.');
}
if (process.connectEnv.name !== 'development') {
warn('"lint" middleware should never be enabled outside of the development environment');
}
checkStack(server.stack);
return function(req, res, next){
next();
}
};
|
| lib/connect/middleware/logger.js |
Log buffer.
|
var buf = [];
|
Default log buffer duration.
|
var defaultBufferDuration = 1000;
|
Log requests with the given options .
Options
format Format string, see below for tokensstream Output stream, defaults to stdoutbuffer Buffer duration, defaults to 1000ms when true
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
return: Function api: public
|
module.exports = function logger(options) {
options = options || {};
var fmt = process.connectEnv.logFormat || options.format,
stream = options.stream || process.stdout,
buffer = options.buffer;
if (buffer) {
var realStream = stream;
setInterval(function(){
if (buf.length) {
realStream.write(buf.join(''), 'ascii');
buf.length = 0;
}
}, typeof buffer === 'number' ? buffer : defaultBufferDuration);
stream = {
write: function(str){
buf.push(str);
}
};
}
return function logger(req, res, next) {
var start = +new Date,
statusCode,
resHeaders,
writeHead = res.writeHead,
end = res.end,
url = req.url;
res.writeHead = function(code, headers){
res.writeHead = writeHead;
res.writeHead(code, headers);
res.statusCode = statusCode = code;
res.headers = resHeaders = headers || {};
};
if (fmt) {
res.end = function(chunk, encoding) {
res.end = end;
res.end(chunk, encoding);
res.responseTime = +new Date - start;
stream.write(format(fmt, req, res) + '\n', 'ascii');
};
} else {
res.end = function(chunk, encoding) {
res.end = end;
res.end(chunk, encoding);
stream.write((req.socket && req.socket.remoteAddress)
+ ' - - [' + (new Date).toUTCString() + ']'
+ ' "' + req.method + ' ' + url
+ ' HTTP/' + req.httpVersionMajor + '.' + req.httpVersionMinor + '" '
+ statusCode + ' ' + (resHeaders['Content-Length'] || '-')
+ ' "' + (req.headers['referer'] || req.headers['referrer'] || '')
+ '" "' + (req.headers['user-agent'] || '') + '"\n', 'ascii');
};
}
next();
};
};
|
| lib/connect/middleware/methodOverride.js |
Module dependencies.
|
var queryString = require('querystring');
|
Valid http methods.
|
var methods = ['GET', 'POST', 'PUT', 'HEAD', 'DELETE', 'OPTIONS'];
|
Pass an optional key to use when checking for
a method override, othewise defaults to __method_.
param: String key return: Function api: public
|
module.exports = function methodOverride(key){
key = key || "_method";
return function methodOverride(req, res, next) {
var method = req.method;
if (typeof req.body === 'object' && key in req.body) {
method = req.body[key];
delete req.body[key];
} else if (req.headers['x-http-method-override']) {
method = req.headers['x-http-method-override'];
}
method = method.toUpperCase();
if (methods.indexOf(method) >= 0) {
req.method = method;
}
next();
};
};
|
| lib/connect/middleware/repl.js |
Module dependencies.
|
var net = require('net'),
_repl = require('repl');
|
Start a REPL on the given unix domain socket path.
Options
sockect Unix domain socket path. Defaults to "/tmp/connect.sock"prompt REPL prompt string. Defaults to "node> "
Example
$ rlwrap telnet /tmp/connect.sock
|
module.exports = function repl(prompt, socket){
prompt = process.connectEnv.replPrompt || prompt || 'node> ';
socket = process.connectEnv.replSocket || socket || '/tmp/connect.sock';
net.createServer(function(stream){
_repl.start(prompt, stream);
}).listen(socket);
return function repl(req, res, next){
next();
}
};
|
| lib/connect/middleware/router.js |
Module dependencies.
|
var parse = require('url').parse,
querystring = require('querystring');
|
Provides Sinatra and Express like routing capabilities.
Examples
connect.router(function(app){
app.get('/user/:id', function(req, res, next){
// populates req.params.id
});
})
param: Function fn return: Function api: public
|
module.exports = function router(fn){
var routes;
if (fn) {
routes = {};
fn.call(this, {
post: method.call(this, 'post'),
get: method.call(this, 'get'),
put: method.call(this, 'put'),
del: method.call(this, 'del')
});
} else {
throw new Error('router provider requires a callback function');
}
function method(name) {
var self = this,
localRoutes = routes[name] = routes[name] || [];
return function(path, fn){
var keys = [];
path = path instanceof RegExp
? path
: normalizePath(path, keys);
localRoutes.push({
fn: fn,
path: path,
keys: keys
});
return self;
};
}
return function router(req, res, next){
var route,
self = this;
(function pass(i){
if (route = match(req, routes, i)) {
req.params = route._params;
try {
route.call(self, req, res, function(err){
if (err === true) {
next();
} else if (err) {
next(err);
} else {
pass(route._index+1);
}
});
} catch (err) {
next(err);
}
} else {
next();
}
})();
};
}
|
| lib/connect/middleware/session/memory.js |
Module dependencies.
|
var sys = require('sys'),
Store = require('./store'),
utils = require('./../../utils'),
Session = require('./session');
|
Initialize MemoryStore with the given options.
param: Object options api: public
|
var MemoryStore = module.exports = function MemoryStore(options) {
options = options || {};
Store.call(this, options);
this.sessions = {};
this.reapInterval = options.reapInterval || 600000;
if (this.reapInterval !== -1) {
setInterval(function(self){
self.reap(self.maxAge);
}, this.reapInterval, this);
}
};
sys.inherits(MemoryStore, Store);
|
Attempt to fetch session by the given sid .
param: String sid param: Function fn api: public
|
MemoryStore.prototype.get = function(sid, fn){
if (sid in this.sessions) {
fn(null, this.sessions[sid]);
} else {
fn();
}
};
|
Commit the given sess object associated with the given sid .
param: String sid param: Session sess param: Function fn api: public
|
MemoryStore.prototype.set = function(sid, sess, fn){
this.sessions[sid] = sess;
fn && fn();
};
|
Destroy the session associated with the given sid .
param: String sid api: public
|
MemoryStore.prototype.destroy = function(sid, fn){
delete this.sessions[sid];
fn && fn();
};
|
Invoke the given callback fn with all active sessions.
param: Function fn api: public
|
MemoryStore.prototype.all = function(fn){
var arr = [],
keys = Object.keys(this.sessions);
for (var i = 0, len = keys.length; i < len; ++i) {
arr.push(this.sessions[keys[i]]);
}
fn(null, arr);
};
|
Clear all sessions.
param: Function fn api: public
|
MemoryStore.prototype.clear = function(fn){
this.sessions = {};
fn && fn();
};
|
Fetch number of sessions.
param: Function fn api: public
|
MemoryStore.prototype.length = function(fn){
fn(null, Object.keys(this.sessions).length);
};
|
| lib/connect/middleware/session/session.js |
Module dependencies.
|
var utils = require('./../../utils');
|
Update lastAccess timestamp.
|
Session.prototype.touch = function(){
this.lastAccess = +new Date;
};
|
Destroy this session.
param: Function fn api: public
|
Session.prototype.destroy = function(fn){
delete this.req.session;
this.req.sessionStore.destroy(this.req.sessionID, fn);
};
|
Regenerate this request's session.
param: Function fn api: public
|
Session.prototype.regenerate = function(fn){
this.req.sessionStore.regenerate(this.req, fn);
};
|
| lib/connect/middleware/session/store.js |
Module dependencies.
|
var Session = require('./session'),
utils = require('./../../utils');
|
Destroy session associated with the given sid
by passing null to Store#get() .
param: String sid param: Function fn api: public
|
Store.prototype.destroy = function(sid, fn){
this.set(sid, null, fn);
};
|
Re-generate the given requests's session.
|
Store.prototype.regenerate = function(req, fn){
var self = this;
this.destroy(req.sessionID, function(err, destroyed){
self.generate();
fn(err, destroyed);
});
};
|
| lib/connect/middleware/session.js |
Module dependencies.
|
var Session = require('./session/session'),
utils = require('./../utils');
|
Setup session store with the given options .
Options
store Session store instancefingerprint Custom fingerprint generating function
param: Object options return: Function api: public
|
exports = module.exports = function sessionSetup(options){
options = options || {};
var key = options.key || 'connect.sid';
var store = options.store || new (require('./session/memory'));
var fingerprint = options.fingerprint || function fingerprint(req) {
return req.headers['user-agent'] || '';
};
var secret = options.secret || "hackme";
return function sessionHandle(req, res, next) {
if (!req.cookies) {
next(new Error("session requires cookieDecoder to work properly"));
return;
}
var writeHead = res.writeHead;
res.writeHead = function(status, headers){
if (req.session) {
req.session.touch();
store.set(req.sessionID, req.session);
}
store.cookie.expires = new Date(Date.now() + store.maxAge);
headers = headers || {};
var cookie = utils.serializeCookie(key, req.sessionID, store.cookie);
if (headers['Set-Cookie']) {
headers['Set-Cookie'] += '\r\nSet-Cookie: ' + cookie;
} else {
headers['Set-Cookie'] = cookie;
}
res.writeHead = writeHead;
return res.writeHead(status, headers);
};
function hash(base) {
return utils.md5(base + fingerprint(req) + secret, 'base64').replace(/=*$/, '');
}
var generate = store.generate = function(){
var base = utils.uid();
var sessionID = base + "." + hash(base);
req.session = new Session(req, sessionID);
req.sessionID = sessionID;
};
req.sessionStore = store;
req.sessionID = req.cookies[key];
if (!req.sessionID) {
generate();
next();
return;
}
var parts = req.sessionID.split('.');
if (parts[1] !== hash(parts[0])) {
generate();
next();
return;
}
store.get(req.sessionID, function (err, sess) {
if (err) {
if (err.errno === process.ENOENT) {
generate();
next();
} else {
next(err);
}
return;
}
if (!sess) {
generate();
next();
return;
}
req.session = new Session(req, sess);
next();
});
};
};
|
Expose constructors.
|
exports.Session = Session;
exports.Store = require('./session/store');
exports.MemoryStore = require('./session/memory');
|
| lib/connect/middleware/staticGzip.js |
Module dependencies.
|
var fs = require('fs'),
parse = require('url').parse
utils = require('../utils'),
path = require('path'),
exec = require('child_process').exec;
|
Expose staticGzip as the module.
|
exports = module.exports = staticGzip;
|
Gzip binary.
|
exports.bin = 'gzip';
|
Flags passed to gzip.
|
exports.flags = '--best';
|
staticGzip gzips statics via whitelist of mime types specified
by the compress option. Once created staticProvider can continue
on to serve the gzipped version of the file.
Options
root Root direction from which to generate gzipped staticscompress Array of mime types serving as a whitelistflags String of flags passed to the binarybin Binary executable defaulting to "gzip"
param: Object options api: public
|
function staticGzip(options){
var options = options || {},
root = options.root,
compress = options.compress,
flags = options.flags || exports.flags,
bin = options.bin || exports.bin;
if (!root) throw new Error('staticGzip root must be set');
if (!compress) throw new Error('staticGzip compress array must be passed');
return function(req, res, next){
if (req.method !== 'GET') return next();
var acceptEncoding = req.headers['accept-encoding'] || '';
if (acceptEncoding && !~acceptEncoding.indexOf('gzip')) return next();
var url = parse(req.url),
filename = path.join(root, url.pathname),
mime = utils.mime.type(filename).split(';')[0];
if (!~compress.indexOf(mime)) return next();
gzipped(filename, function(err, path, ext){
if (err && err.errno === process.ENOENT) {
next();
if (err.path.indexOf('.gz') === err.path.length - 3) {
gzip(filename, path, flags, bin);
}
} else if (err) {
next(err);
} else {
req.url = url.pathname + ext;
var writeHead = res.writeHead;
res.writeHead = function(status, headers){
headers = headers || {};
res.writeHead = writeHead;
headers['Content-Type'] = mime;
headers['Content-Encoding'] = 'gzip';
res.writeHead(status, headers);
};
next();
}
});
}
};
|
| lib/connect/middleware/staticProvider.js |
Module dependencies.
|
var fs = require('fs'),
Path = require('path'),
utils = require('../utils'),
Buffer = require('buffer').Buffer,
parseUrl = require('url').parse,
queryString = require('querystring');
|
Default browser cache maxAge of one year.
|
const MAX_AGE = 31557600000;
|
File buffer cache.
|
var _cache = {};
|
Static file server.
Options
root Root path from which to serve static files.maxAge Browser cache maxAge in millisecondscache When true cache files in memory indefinitely,
until invalidated by a conditional GET request.
When given, maxAge will be derived from this value.
param: Object options return: Function api: public
|
module.exports = function staticProvider(options){
var cache, maxAge, root;
if (typeof options == 'string') {
root = options;
maxAge = MAX_AGE;
} else {
options = options || {};
maxAge = options.maxAge;
root = process.connectEnv.staticRoot || options.root || process.cwd();
cache = options.cache;
if (cache && !maxAge) maxAge = cache;
maxAge = maxAge || MAX_AGE;
}
return function staticProvider(req, res, next) {
if (req.method != 'GET' && req.method != 'HEAD') return next();
var hit,
head = req.method == 'HEAD',
filename, url = parseUrl(req.url);
if (~url.pathname.indexOf('..')) {
return forbidden(res);
}
filename = Path.join(root, queryString.unescape(url.pathname));
if (filename[filename.length - 1] === '/') {
filename += "index.html";
}
if (cache && !conditionalGET(req) && (hit = _cache[req.url])) {
res.writeHead(200, hit.headers);
res.end(head ? undefined : hit.body);
return;
}
fs.stat(filename, function(err, stat){
if (err) {
return err.errno === process.ENOENT
? next()
: next(err);
} else if (stat.isDirectory()) {
return next();
}
function onRead(err, data) {
if (err) return next(err);
var headers = {
"Content-Type": utils.mime.type(filename),
"Content-Length": stat.size,
"Last-Modified": stat.mtime.toUTCString(),
"Cache-Control": "public max-age=" + (maxAge / 1000),
"ETag": etag(stat)
};
if (!modified(req, headers)) {
return notModified(res, headers);
}
res.writeHead(200, headers);
res.end(head ? undefined : data);
if (cache) {
_cache[req.url] = {
headers: headers,
body: data
};
}
}
fs.readFile(filename, onRead);
});
};
};
|
Clear the memory cache for key or the entire store.
param: String key api: public
|
exports.clearCache = function(key){
if (key) {
delete _cache[key];
} else {
_cache = {};
}
};
|
| lib/connect/middleware/vhost.js |
Setup vhost for the given hostname and server .
Examples
connect.createServer(
connect.vhost('foo.com',
connect.createServer(...middleware...)
),
connect.vhost('bar.com',
connect.createServer(...middleware...)
)
);
param: String hostname param: Server server return: Function api: public
|
module.exports = function vhost(hostname, server){
if (!hostname) {
throw new Error('vhost hostname required');
}
if (!server) {
throw new Error('vhost server required');
}
return function vhost(req, res, next){
if (!req.headers.host) next();
var host = req.headers.host.split(':')[0];
if (host === hostname) {
server.handle(req, res, next);
} else {
next();
}
};
};
|