lazier and lazier (plus early static handling)

This commit is contained in:
AJ ONeal 2015-03-06 03:04:51 +00:00
parent 8827da6478
commit a21c503b6e
2 changed files with 119 additions and 89 deletions

View File

@ -1,9 +1,10 @@
'use strict'; 'use strict';
var http = require('http');
var escapeRe = require('escape-string-regexp');
module.exports.create = function (securePort, insecurePort, redirects) { module.exports.create = function (securePort, insecurePort, redirects) {
var PromiseA = require('bluebird').Promise;
var http = require('http');
var escapeRe;
function redirectHttps(req, res) { function redirectHttps(req, res) {
var insecureRedirects; var insecureRedirects;
var host = req.headers.host || ''; var host = req.headers.host || '';
@ -20,6 +21,11 @@ module.exports.create = function (securePort, insecurePort, redirects) {
return hlen; return hlen;
}).forEach(function (redirect) { }).forEach(function (redirect) {
var origHost = host; var origHost = host;
if (!escapeRe) {
escapeRe = require('escape-string-regexp');
}
// TODO if '*' === hostname[0], omit '^' // TODO if '*' === hostname[0], omit '^'
host = host.replace( host = host.replace(
new RegExp('^' + escapeRe(redirect.from.hostname)) new RegExp('^' + escapeRe(redirect.from.hostname))
@ -42,11 +48,11 @@ module.exports.create = function (securePort, insecurePort, redirects) {
+ '<html>\n' + '<html>\n'
+ '<head>\n' + '<head>\n'
+ ' <style>* { background-color: white; color: white; text-decoration: none; }</style>\n' + ' <style>* { background-color: white; color: white; text-decoration: none; }</style>\n'
+ ' <META http-equiv="refresh" content="0;URL=' + encodeURI(newLocation) + '">\n' + ' <META http-equiv="refresh" content="0;URL=' + newLocation + '">\n'
+ '</head>\n' + '</head>\n'
+ '<body style="display: none;">\n' + '<body style="display: none;">\n'
+ ' <p>You requested an insecure resource. Please use this instead: \n' + ' <p>You requested an insecure resource. Please use this instead: \n'
+ ' <a href="' + encodeURI(newLocation) + '">' + encodeURI(newLocation) + '</a></p>\n' + ' <a href="' + newLocation + '">' + newLocation + '</a></p>\n'
+ '</body>\n' + '</body>\n'
+ '</html>\n' + '</html>\n'
; ;
@ -86,4 +92,6 @@ module.exports.create = function (securePort, insecurePort, redirects) {
console.log("\nListening on https://localhost:" + insecureServer.address().port); console.log("\nListening on https://localhost:" + insecureServer.address().port);
console.log("(redirecting all traffic to https)\n"); console.log("(redirecting all traffic to https)\n");
}); });
return PromiseA.resolve(insecureServer);
}; };

View File

@ -2,6 +2,7 @@
module.exports.create = function (securePort, certsPath, vhostsdir) { module.exports.create = function (securePort, certsPath, vhostsdir) {
var PromiseA = require('bluebird').Promise; var PromiseA = require('bluebird').Promise;
var serveStatic;
var https = require('https'); var https = require('https');
var fs = require('fs'); var fs = require('fs');
var path = require('path'); var path = require('path');
@ -28,7 +29,7 @@ module.exports.create = function (securePort, certsPath, vhostsdir) {
return dummyCerts; return dummyCerts;
} }
function handleAppScopedError(req, res, fn) { function handleAppScopedError(domaininfo, req, res, fn) {
function next(err) { function next(err) {
if (!err) { if (!err) {
fn(req, res); fn(req, res);
@ -99,6 +100,7 @@ module.exports.create = function (securePort, certsPath, vhostsdir) {
} }
function loadDomainMounts(domaininfo) { function loadDomainMounts(domaininfo) {
var connectContext = {};
var appContext; var appContext;
// should order and group by longest domain, then longest path // should order and group by longest domain, then longest path
@ -119,6 +121,7 @@ module.exports.create = function (securePort, certsPath, vhostsdir) {
console.log('[log] [once] Preparing mount for', domaininfo.hostname + '/' + domaininfo.dirpathname); console.log('[log] [once] Preparing mount for', domaininfo.hostname + '/' + domaininfo.dirpathname);
domainMergeMap[domaininfo.hostname].mountsMap['/' + domaininfo.dirpathname] = function (req, res, next) { domainMergeMap[domaininfo.hostname].mountsMap['/' + domaininfo.dirpathname] = function (req, res, next) {
function nextify() {
if (appContext) { if (appContext) {
appContext(req, res, next); appContext(req, res, next);
return; return;
@ -135,14 +138,14 @@ module.exports.create = function (securePort, certsPath, vhostsdir) {
// we always add it explicitly // we always add it explicitly
function localAppWrapped(req, res) { function localAppWrapped(req, res) {
console.log('[debug]', domaininfo.hostname + '/' + domaininfo.pathname, req.url); console.log('[debug]', domaininfo.hostname + '/' + domaininfo.pathname, req.url);
localApp(req, res, handleAppScopedError(req, res, function (req, res) { localApp(req, res, handleAppScopedError(domaininfo, req, res, function (req, res) {
if (!serveFavicon) { if (!serveFavicon) {
serveFavicon = require('serve-favicon')(path.join(__dirname, '..', 'public', 'favicon.ico')); serveFavicon = require('serve-favicon')(path.join(__dirname, '..', 'public', 'favicon.ico'));
} }
// TODO redirect GET /favicon.ico to GET (req.headers.referer||'') + /favicon.ico // TODO redirect GET /favicon.ico to GET (req.headers.referer||'') + /favicon.ico
// TODO other common root things - robots.txt, app-icon, etc // TODO other common root things - robots.txt, app-icon, etc
serveFavicon(req, res, handleAppScopedError(req, res, function (req, res) { serveFavicon(req, res, handleAppScopedError(domaininfo, req, res, function (req, res) {
res.writeHead(404); res.writeHead(404);
res.end( res.end(
"<html>" "<html>"
@ -194,6 +197,23 @@ module.exports.create = function (securePort, certsPath, vhostsdir) {
+ 'or default error app." } }'); + 'or default error app." } }');
} }
}); });
}
if (!serveStatic) {
serveStatic = require('serve-static');
}
if (!connectContext.static) {
console.log('[static]', path.join(vhostsdir, domaininfo.dirname, 'public'));
connectContext.static = serveStatic(path.join(vhostsdir, domaininfo.dirname, 'public'));
}
if (/^\/api\//.test(req.url)) {
nextify();
return;
}
connectContext.static(req, res, nextify);
}; };
domainMergeMap[domaininfo.hostname].apps.use( domainMergeMap[domaininfo.hostname].apps.use(
'/' + domaininfo.pathname '/' + domaininfo.pathname
@ -302,7 +322,7 @@ module.exports.create = function (securePort, certsPath, vhostsdir) {
} }
return forEachAsync(domainMergeMap[vhost].apps, function (fn) { return forEachAsync(domainMergeMap[vhost].apps, function (fn) {
return new PromiseA(function (resolve) { return new PromiseA(function (resolve, reject) {
function next(err) { function next(err) {
if (err) { if (err) {
reject(err); reject(err);
@ -341,7 +361,7 @@ module.exports.create = function (securePort, certsPath, vhostsdir) {
return; return;
}); });
}); });
}; }
function loadCerts(domainname) { function loadCerts(domainname) {
// TODO make async // TODO make async
@ -349,15 +369,16 @@ module.exports.create = function (securePort, certsPath, vhostsdir) {
// Also, once we load Let's Encrypt, it's lights out for v0.10 // Also, once we load Let's Encrypt, it's lights out for v0.10
var certsPath = path.join(vhostsdir, domainname, 'certs'); var certsPath = path.join(vhostsdir, domainname, 'certs');
var secOpts;
try { try {
var nodes = fs.readdirSync(path.join(certsPath, 'server')); var nodes = fs.readdirSync(path.join(certsPath, 'server'));
var keyNode = nodes.filter(function (node) { return /\.key\.pem$/.test(node); })[0]; var keyNode = nodes.filter(function (node) { return /\.key\.pem$/.test(node); })[0];
var crtNode = nodes.filter(function (node) { return /\.crt\.pem$/.test(node); })[0]; var crtNode = nodes.filter(function (node) { return /\.crt\.pem$/.test(node); })[0];
var secOpts = { secOpts = {
key: fs.readFileSync(path.join(certsPath, 'server', keyNode)) key: fs.readFileSync(path.join(certsPath, 'server', keyNode))
, cert: fs.readFileSync(path.join(certsPath, 'server', crtNode)) , cert: fs.readFileSync(path.join(certsPath, 'server', crtNode))
} };
if (fs.existsSync(path.join(certsPath, 'ca'))) { if (fs.existsSync(path.join(certsPath, 'ca'))) {
secOpts.ca = fs.readdirSync(path.join(certsPath, 'ca')).filter(function (node) { secOpts.ca = fs.readdirSync(path.join(certsPath, 'ca')).filter(function (node) {
@ -419,7 +440,8 @@ module.exports.create = function (securePort, certsPath, vhostsdir) {
if (!secureContexts[domainname]) { if (!secureContexts[domainname]) {
console.log('[log] Loading certs for', domainname); console.log('[log] Loading certs for', domainname);
secureContexts[domainname] = loadCerts(domainname); // TODO keep trying to find the cert in case it's uploaded late?
secureContexts[domainname] = loadCerts(domainname) || secureContexts.dummy;
} }
// workaround for v0.12 / v1.2 backwards compat bug // workaround for v0.12 / v1.2 backwards compat bug
@ -472,4 +494,4 @@ module.exports.create = function (securePort, certsPath, vhostsdir) {
} }
return runServer(); return runServer();
} };