164 lines
4.4 KiB
JavaScript
164 lines
4.4 KiB
JavaScript
'use strict';
|
|
|
|
var escapeStringRegexp = require('escape-string-regexp');
|
|
var runApi = require('./package-server-apis').runApi;
|
|
var layerItUp = require('./package-server-static').layerItUp;
|
|
|
|
function compileVhosts(vhostsMap) {
|
|
var results = {
|
|
patterns: []
|
|
, conflictsMap: {}
|
|
, matchesMap: {}
|
|
};
|
|
|
|
// compli
|
|
Object.keys(vhostsMap).forEach(function (key) {
|
|
var vhost = vhostsMap[key];
|
|
var bare;
|
|
var www;
|
|
|
|
if ('.' === vhost.hostname[0]) {
|
|
// for consistency
|
|
// TODO this should happen at the database level
|
|
vhost.hostname = '*' + vhost.hostname;
|
|
}
|
|
|
|
if ('*' === vhost.hostname[0]) {
|
|
// TODO check that we are not trying to redirect a tld (.com, .co.uk, .org, etc)
|
|
// tlds should follow the global policy
|
|
if (vhost.hostname[1] && '.' !== vhost.hostname[1]) {
|
|
// this is not a good place to throw as the consequences of a bug would be
|
|
// very bad, but errors should never be silent, so we'll compromise
|
|
console.warn("[NON-FATAL ERROR]: ignoring pattern '" + vhost.hostname + "'");
|
|
results.conflictsMap[vhost.hostname] = vhost;
|
|
}
|
|
|
|
// nix the '*' for easier matching
|
|
vhost.hostname = vhost.hostname.slice(1);
|
|
// except the default
|
|
if (!vhost.hostname) {
|
|
vhost.hostname = '*';
|
|
}
|
|
if (results.conflictsMap[vhost.hostname]) {
|
|
console.warn("[NON-FATAL ERROR]: duplicate entry for pattern '" + vhost.hostname + "'");
|
|
}
|
|
|
|
results.conflictsMap[vhost.hostname] = vhost;
|
|
results.patterns.push(vhost);
|
|
return;
|
|
}
|
|
|
|
bare = vhost.hostname.replace(/^www\./i, '');
|
|
www = vhost.hostname.replace(/^(www\.)?/i, 'www.');
|
|
|
|
results.matchesMap[bare] = vhost;
|
|
results.matchesMap[www] = vhost;
|
|
});
|
|
|
|
results.patterns.sort(function (a, b) {
|
|
return b.id.length - a.id.length;
|
|
});
|
|
|
|
return results;
|
|
}
|
|
|
|
function mapToApp(opts, req, res, next) {
|
|
// opts = { config, deps, services }
|
|
var vhost;
|
|
var router;
|
|
var pkgConf = opts.config;
|
|
|
|
if (!pkgConf.vhostConf) {
|
|
pkgConf.vhostConf = compileVhosts(pkgConf.vhostsMap);
|
|
}
|
|
|
|
//console.log('req.hostname');
|
|
//console.log(req.hostname);
|
|
|
|
//console.log(Object.keys(pkgConf.vhostConf.matchesMap));
|
|
|
|
// TODO www vs no-www?
|
|
vhost = pkgConf.vhostConf.matchesMap[req.hostname];
|
|
|
|
if (!vhost) {
|
|
pkgConf.vhostConf.patterns.some(function (pkg) {
|
|
// TODO this should be done in the compile phase
|
|
if ('*' === pkg.id[0] && '.' === pkg.id[1]) {
|
|
pkg.id = pkg.id.slice(1);
|
|
}
|
|
if (pkg.id === req.hostname.slice(req.hostname.length - pkg.id.length)) {
|
|
vhost = pkg;
|
|
return true;
|
|
}
|
|
});
|
|
}
|
|
|
|
if (!vhost) {
|
|
next();
|
|
return;
|
|
}
|
|
|
|
// TODO don't modify route here (or in subloaders), modify some other variable instead
|
|
// TODO precompile RegExps and pre-sort app vs api
|
|
vhost.pathnames.some(function (routes) {
|
|
var pathname = routes.pathname;
|
|
if ('/' === pathname) {
|
|
pathname = '';
|
|
}
|
|
|
|
if (!routes._re_app) {
|
|
routes._re_app = new RegExp(escapeStringRegexp(pathname) + '(#|\\/|\\?|$)');
|
|
//console.log('[static re]', routes._re_app);
|
|
}
|
|
|
|
if (!routes._re_api) {
|
|
// TODO allow for special apis that do not follow convention (.well_known, webfinger, oauth3.html, etc)
|
|
routes._re_api = new RegExp(escapeStringRegexp(pathname + '/api/') + '([\\w\\.\\-]+)(\\/|\\?|$)');
|
|
//console.log('[api re]', routes._re_api);
|
|
}
|
|
|
|
if (routes._re_app.test(req.url)) {
|
|
router = routes;
|
|
return true;
|
|
}
|
|
|
|
// no need to test for api yet as it is a postfix
|
|
});
|
|
|
|
if (!router) {
|
|
//console.log('[no router for]', req.url);
|
|
next();
|
|
return;
|
|
}
|
|
|
|
// TODO .well-known can be an API (webfinger, letsencrypt, oauth3)
|
|
// or static (...???)
|
|
|
|
if (!router._re_api.test(req.url)) {
|
|
//console.log('[static router]');
|
|
//console.log(router._re_api, req.url);
|
|
layerItUp(pkgConf, router, req, res, function (err) {
|
|
if (err) {
|
|
next(err);
|
|
return;
|
|
}
|
|
|
|
if (/\/\.well-known([\/?]|$)/.test(req.url)) {
|
|
console.log('[TODO] handle .well-known as API');
|
|
// rewrite api as /api/org.ietf/.well-known ?
|
|
// pass through simply as /.well-known ?
|
|
// runApi(opts, router, req, res, next)
|
|
}
|
|
|
|
next();
|
|
});
|
|
return;
|
|
}
|
|
|
|
//console.log('[api router]', req.url);
|
|
return runApi(opts, router, req, res, next);
|
|
}
|
|
|
|
module.exports.compileVhosts = compileVhosts;
|
|
module.exports.mapToApp = mapToApp;
|