hem
Version:
stitches CommonJS, and ties up other lose ends of web-app development.
192 lines (176 loc) • 6.41 kB
JavaScript
// Generated by CoffeeScript 1.12.7
(function() {
var checkForRedirect, connect, createRoutingProxy, fs, http, httpProxy, log, mime, patchServerResponseForRedirects, server, utils;
connect = require('connect');
mime = require('connect')["static"].mime;
httpProxy = require('http-proxy');
http = require('http');
fs = require('fs');
utils = require('./utils');
log = require('./log');
server = {};
server.start = function(hem) {
var app, options;
app = connect();
app.use(server.middleware(hem));
options = hem.options.hem;
if (options.host === "*") {
http.createServer(app).listen(options.port);
} else {
http.createServer(app).listen(options.port, options.host);
}
return app;
};
server.middleware = function(hem) {
var app, backend, display, i, j, k, l, len, len1, len2, len3, options, pkg, ref, ref1, ref2, ref3, ref4, route, statics, value;
backend = connect();
options = hem.options.hem;
statics = [];
ref = options != null ? options["static"] : void 0;
for (route in ref) {
value = ref[route];
statics.push({
url: route,
path: value
});
}
ref1 = hem.apps;
for (i = 0, len = ref1.length; i < len; i++) {
app = ref1[i];
log.info("> Apply route mappings for application: <green>" + app.name + "</green>");
ref2 = app.packages;
for (j = 0, len1 = ref2.length; j < len1; j++) {
pkg = ref2[j];
if (options.baseAppRoute) {
pkg.route = utils.cleanRoute(options.baseAppRoute, pkg.route);
}
log.info(" - Mapping route <yellow>" + pkg.route + "</yellow> to <yellow>" + pkg.target + "</yellow>");
}
ref3 = app["static"];
for (k = 0, len2 = ref3.length; k < len2; k++) {
route = ref3[k];
if (options.baseAppRoute) {
route.url = utils.cleanRoute(options.baseAppRoute, route.url);
}
log.info(" - Mapping static <yellow>" + route.url + "</yellow> to <yellow>" + route.path + "</yellow>");
statics.push(route);
}
}
for (l = 0, len3 = statics.length; l < len3; l++) {
route = statics[l];
if (!fs.existsSync(route.path)) {
log.errorAndExit("The resource <yellow>" + route.path + "</yellow> not found for static mapping <yellow>" + route.url + "</yellow>");
}
if (fs.lstatSync(route.path).isDirectory()) {
backend.use(route.url, checkForRedirect());
backend.use(route.url, connect["static"](route.path));
} else {
backend.use(route.url, (function(route) {
return function(req, res) {
return fs.readFile(route.path, function(err, data) {
if (err) {
res.writeHead(404);
return res.end(JSON.stringify(err));
} else {
res.writeHead(200);
return res.end(data);
}
});
};
})(route));
}
}
ref4 = options.proxy;
for (route in ref4) {
value = ref4[route];
display = value.host + ":" + (value.port || 80) + value.path;
log.info("> Proxy requests <yellow>" + route + "</yellow> to <yellow>" + display + "</yellow>");
backend.use(route, createRoutingProxy(value, options.host + ":" + options.port));
}
return function(req, res, next) {
var len4, m, ref5, ref6, str, url;
url = ((ref5 = require("url").parse(req.url)) != null ? ref5.pathname.toLowerCase() : void 0) || "";
if (url.match(/(\.js|\.css)$/)) {
ref6 = hem.apps;
for (m = 0, len4 = ref6.length; m < len4; m++) {
app = ref6[m];
if (pkg = app.isMatchingRoute(url)) {
str = pkg.build();
res.charset = 'utf-8';
res.setHeader('Content-Type', mime.lookup(pkg.target));
res.setHeader('Content-Length', Buffer.byteLength(str));
res.end((req.method === 'HEAD' && null) || str);
return;
}
}
}
return backend.handle(req, res, next);
};
};
checkForRedirect = function() {
return function(req, res, next) {
var pathname;
pathname = require("url").parse(req.originalUrl).pathname;
if (req.url === "/" && !utils.endsWith(pathname, "/")) {
pathname += '/';
res.statusCode = 301;
res.setHeader('Location', pathname);
return res.end('Redirecting to ' + pathname);
} else {
return next();
}
};
};
createRoutingProxy = function(options, returnHost) {
var defaultPort, proxy, routingProxyOptions;
if (options.https) {
routingProxyOptions = {
target: {
https: true
}
};
defaultPort = 443;
} else {
routingProxyOptions = {};
defaultPort = 80;
}
proxy = new httpProxy.RoutingProxy(routingProxyOptions);
options.path || (options.path = "");
options.port || (options.port = defaultPort);
options.patchRedirect || (options.patchRedirect = true);
if (options.patchRedirect) {
proxy.once("start", function(req, res) {
return patchServerResponseForRedirects(options.host, returnHost);
});
}
return function(req, res, next) {
req.url = "" + options.path + req.url;
req.headers.host = options.host;
return proxy.proxyRequest(req, res, options);
};
};
patchServerResponseForRedirects = function(fromHost, returnHost) {
var writeHead;
writeHead = http.ServerResponse.prototype.writeHead;
return http.ServerResponse.prototype.writeHead = function(status) {
var cookie, headers, i, len, newLocation, newSetCookie, oldLocation, ref;
headers = this._headers || {};
if (status === 301 || status === 302) {
oldLocation = new RegExp("s?:\/\/" + fromHost + ":?[0-9]*");
newLocation = "://" + returnHost;
headers.location = headers.location.replace(oldLocation, newLocation);
}
if ('set-cookie' in headers) {
newSetCookie = [];
ref = headers['set-cookie'];
for (i = 0, len = ref.length; i < len; i++) {
cookie = ref[i];
newSetCookie.push(cookie.replace(/; Secure; HttpOnly/, ''));
}
headers['set-cookie'] = newSetCookie;
}
return writeHead.apply(this, arguments);
};
};
module.exports = server;
}).call(this);