'use strict'; module.exports.create = function (deps, conf, greenlockMiddleware) { var express = require('express'); var app = express(); var adminApp = require('./admin').create(deps, conf); var domainMatches = require('../match-domain').match; var adminDomains = [ /\blocalhost\.admin\./ , /\blocalhost\.alpha\./ , /\badmin\.localhost\./ , /\balpha\.localhost\./ ]; // We handle both HTTPS and HTTP traffic on the same ports, and we want to redirect // any unencrypted requests to the same port they came from unless it came in on // the default HTTP port, in which case there wont be a port specified in the host. var redirecters = {}; function redirectHttps(req, res, next) { var port = req.headers.host.split(':')[1]; if (!redirecters[port]) { redirecters[port] = require('redirect-https')({ port: port , trustProxy: conf.http.trustProxy }); } redirecters[port](req, res, next); } function handleAdmin(req, res, next) { var admin = adminDomains.some(function (re) { return re.test(req.headers.host); }); if (admin) { adminApp(req, res); } else { next(); } } function respond404(req, res) { res.writeHead(404); res.end('Not Found'); } function createProxyRoute(mod) { // This is the easiest way to override the createConnections function the proxy // module uses, but take note the since we don't have control over where this is // called the extra options availabled will be different. var agent = new require('http').Agent({}); agent.createConnection = deps.net.createConnection; var proxy = require('http-proxy').createProxyServer({ agent: agent , target: 'http://' + mod.address , xfwd: true , toProxy: true }); // We want to override the default value for some headers with the extra information we // have available to us in the opts object attached to the connection. proxy.on('proxyReq', function (proxyReq, req) { var conn = req.connection; var opts = conn.__opts; proxyReq.setHeader('X-Forwarded-For', opts.remoteAddress || conn.remoteAddress); }); proxy.on('error', function (err, req, res) { console.log(err); res.statusCode = 502; res.setHeader('Content-Type', 'text/html'); res.setHeader('Connection', 'close'); res.end(require('../proxy-err-resp').getRespBody(err, conf.debug)); }); return function (req, res, next) { var hostname = req.headers.host.split(':')[0]; var relevant = mod.domains.some(function (pattern) { return domainMatches(pattern, hostname); }); if (relevant) { proxy.web(req, res); } else { next(); } }; } function createStaticRoute(mod) { var getStaticApp, staticApp; if (/:hostname/.test(mod.root)) { staticApp = {}; getStaticApp = function (hostname) { if (!staticApp[hostname]) { staticApp[hostname] = express.static(mod.root.replace(':hostname', hostname)); } return staticApp[hostname]; }; } else { staticApp = express.static(mod.root); getStaticApp = function () { return staticApp; }; } return function (req, res, next) { var hostname = req.headers.host.split(':')[0]; var relevant = mod.domains.some(function (pattern) { return domainMatches(pattern, hostname); }); if (relevant) { getStaticApp(hostname)(req, res, next); } else { next(); } }; } app.use(greenlockMiddleware); app.use(redirectHttps); app.use(handleAdmin); (conf.http.modules || []).forEach(function (mod) { if (mod.name === 'proxy') { app.use(createProxyRoute(mod)); } else if (mod.name === 'static') { app.use(createStaticRoute(mod)); } else { console.warn('unknown HTTP module', mod); } }); app.use(respond404); return require('http').createServer(app); };