Files
deployd/lib/server.js
2012-04-18 15:00:06 -07:00

171 lines
3.8 KiB
JavaScript

/**
* Dependencies
*/
var express = require('express')
, parse = require('url').parse
, keys = require('./collections/keys')
;
/**
* Http server as a middleware
*/
var middleware = function (req, res, next) {
next();
};
/**
* Expose the mdoq object over http.
*/
middleware.listen = function (callback) {
var server = this.server = middleware.server = express.createServer(function (req, res, next) {
var origin = req.header('Origin');
var path = origin && parse(origin);
if (origin == 'null' || (path && path.hostname == 'localhost')) {
res.header('Access-Control-Allow-Origin', '*');
res.header('Access-Control-Allow-Credentials', 'true');
res.header('Access-Control-Allow-Methods', 'GET, POST, PUT, DELETE, OPTIONS');
res.header("Access-Control-Allow-Headers", 'Origin, Accept, Content-Type');
if(req.method === 'OPTIONS') {
res.send('OK');
return;
}
}
// by default pause the request
req.pause();
if(req.method === 'GET' || req.method === 'DELETE') return next();
// check for json content type
var contentType = req.header('Content-Type')
, isJSON = contentType && contentType.indexOf('application/json') > -1
;
// for non files, default to application/json
if(!isJSON && req.url.indexOf('.') === -1) {
isJSON = true;
}
// only buffer JSON
// everything else
// should stream!
if(isJSON) {
var buf = '', err;
// TODO: use an actual buffer
// buffer the data
req.on('data', function (data) {
buf += data;
});
// until the stream ends
req.on('end', function () {
try {
// parse the buffer or create an empty body
req.body = buf ? JSON.parse(buf.toString()) : {};
} catch(e) {err = e}
next(err);
});
// start reading
req.resume();
} else {
next();
}
}, express.cookieParser())
// where to serve from
var url = parse(this.url || 'http://localhost:2403');
// port
var port = url.port || 2403;
// host
var hostname = url.hostname || 'localhost';
process.url = url;
// remote flag / remote auth
server.use(function (req, res, next) {
req.isRemote = true;
// root auth
var rawHdr = req.headers['x-dssh-key']
, authErr = {status: 401}
, strength
, dssh;
// if dashboard
if(!rawHdr && req.url.indexOf('/__dashboard') === 0) {
rawHdr = req.query.key;
}
if(rawHdr) {
try {
dssh = JSON.parse(rawHdr);
strength = Object.keys(dssh).length;
} catch(e) {
return next(authErr);
}
// dont even try to authenticate keys that arent secure
if(req.isRemote && !(dssh && dssh._id && (strength > 2))) return next(authErr);
// authenticate key
keys.get(dssh, function (err, key) {
if(req.isRemote && !key) {
// remote requests must have a registered key
return next(authErr);
} else {
req.isRoot = true;
next();
}
})
} else {
next();
}
});
// proxy requests into the current mdoq stack
// executing the stack when a request comes in
server.use(this.proxy());
// error handling
server.error(function (err, req, res, next) {
if(err instanceof Error) {
res.statusCode = 500;
res.send({message: err.message});
} else {
res.statusCode = err.status || 400;
res.send(err);
}
});
// start the server
server.listen(port, hostname, callback);
// chainable
return this;
};
/**
* Stop the server from accepting new connections.
*/
middleware.close = function () {
this.server.close();
};
/**
* Export the middleware
*/
module.exports = middleware;