implemented HTTP 301 redirect with glob matching
This commit is contained in:
parent
0047ae69f4
commit
d16f857fca
|
@ -155,7 +155,7 @@ function readConfigAndRun(args) {
|
||||||
|
|
||||||
if (ports.length === 0) {
|
if (ports.length === 0) {
|
||||||
// I don't think we want to prevent the rest of the app from running in
|
// I don't think we want to prevent the rest of the app from running in
|
||||||
// this case like we do for TCP, do don't call reject.
|
// this case like we do for TCP, so don't call reject.
|
||||||
console.warn('could not bind to the desired ports for DNS');
|
console.warn('could not bind to the desired ports for DNS');
|
||||||
Object.keys(failed).forEach(function (key) {
|
Object.keys(failed).forEach(function (key) {
|
||||||
console.log('[error bind]', key, failed[key].code);
|
console.log('[error bind]', key, failed[key].code);
|
||||||
|
|
|
@ -22,6 +22,12 @@ http:
|
||||||
allow_insecure: false
|
allow_insecure: false
|
||||||
primary_domain: localhost.foo.daplie.me
|
primary_domain: localhost.foo.daplie.me
|
||||||
modules:
|
modules:
|
||||||
|
- name: redirect
|
||||||
|
domains:
|
||||||
|
- localhost.beta.daplie.me
|
||||||
|
status: 301
|
||||||
|
from: /old/path/*/other/*
|
||||||
|
to: /path/new/:2/something/:1
|
||||||
- name: proxy
|
- name: proxy
|
||||||
domains:
|
domains:
|
||||||
- localhost.daplie.me
|
- localhost.daplie.me
|
||||||
|
|
|
@ -0,0 +1,30 @@
|
||||||
|
'use strict';
|
||||||
|
|
||||||
|
module.exports.match = function (pattern, domainname) {
|
||||||
|
// Everything matches '*'
|
||||||
|
if (pattern === '*') {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (/^\*./.test(pattern)) {
|
||||||
|
// get rid of the leading "*." to more easily check the servername against it
|
||||||
|
pattern = pattern.slice(2);
|
||||||
|
return pattern === domainname.slice(-pattern.length);
|
||||||
|
}
|
||||||
|
|
||||||
|
// pattern doesn't contains any wildcards, so exact match is required
|
||||||
|
return pattern === domainname;
|
||||||
|
};
|
||||||
|
|
||||||
|
module.exports.separatePort = function (fullHost) {
|
||||||
|
var match = /^(.*?)(:\d+)?$/.exec(fullHost);
|
||||||
|
|
||||||
|
if (match[2]) {
|
||||||
|
match[2] = match[2].replace(':', '');
|
||||||
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
|
host: match[1]
|
||||||
|
, port: match[2]
|
||||||
|
};
|
||||||
|
};
|
|
@ -1,17 +0,0 @@
|
||||||
'use strict';
|
|
||||||
|
|
||||||
module.exports.match = function (pattern, servername) {
|
|
||||||
// Everything matches '*'
|
|
||||||
if (pattern === '*') {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (/^\*./.test(pattern)) {
|
|
||||||
// get rid of the leading "*." to more easily check the servername against it
|
|
||||||
pattern = pattern.slice(2);
|
|
||||||
return pattern === servername.slice(-pattern.length);
|
|
||||||
}
|
|
||||||
|
|
||||||
// pattern doesn't contains any wildcards, so exact match is required
|
|
||||||
return pattern === servername;
|
|
||||||
};
|
|
|
@ -4,7 +4,8 @@ module.exports.create = function (deps, conf, greenlockMiddleware) {
|
||||||
var express = require('express');
|
var express = require('express');
|
||||||
var app = express();
|
var app = express();
|
||||||
var adminApp = require('./admin').create(deps, conf);
|
var adminApp = require('./admin').create(deps, conf);
|
||||||
var domainMatches = require('../match-domain').match;
|
var domainMatches = require('../domain-utils').match;
|
||||||
|
var separatePort = require('../domain-utils').separatePort;
|
||||||
var proxyRoutes = [];
|
var proxyRoutes = [];
|
||||||
|
|
||||||
var adminDomains = [
|
var adminDomains = [
|
||||||
|
@ -14,8 +15,16 @@ module.exports.create = function (deps, conf, greenlockMiddleware) {
|
||||||
, /\balpha\.localhost\./
|
, /\balpha\.localhost\./
|
||||||
];
|
];
|
||||||
|
|
||||||
|
function moduleMatchesHost(req, mod) {
|
||||||
|
var host = separatePort(req.headers.host).host;
|
||||||
|
|
||||||
|
return mod.domains.some(function (pattern) {
|
||||||
|
return domainMatches(pattern, host);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
function verifyHost(fullHost) {
|
function verifyHost(fullHost) {
|
||||||
var host = /^(.*?)(:\d+)?$/.exec(fullHost)[1];
|
var host = separatePort(fullHost).host;
|
||||||
|
|
||||||
if (host === 'localhost') {
|
if (host === 'localhost') {
|
||||||
return fullHost.replace(host, 'localhost.daplie.me');
|
return fullHost.replace(host, 'localhost.daplie.me');
|
||||||
|
@ -50,7 +59,7 @@ module.exports.create = function (deps, conf, greenlockMiddleware) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
var port = (/:(\d+)$/.exec(req.headers.host) || [])[1];
|
var port = separatePort(req.headers.host).port;
|
||||||
if (!redirecters[port]) {
|
if (!redirecters[port]) {
|
||||||
redirecters[port] = require('redirect-https')({
|
redirecters[port] = require('redirect-https')({
|
||||||
port: port
|
port: port
|
||||||
|
@ -115,24 +124,14 @@ module.exports.create = function (deps, conf, greenlockMiddleware) {
|
||||||
|
|
||||||
return {
|
return {
|
||||||
web: function (req, res, next) {
|
web: function (req, res, next) {
|
||||||
var hostname = req.headers.host.split(':')[0];
|
if (moduleMatchesHost(req, mod)) {
|
||||||
var relevant = mod.domains.some(function (pattern) {
|
|
||||||
return domainMatches(pattern, hostname);
|
|
||||||
});
|
|
||||||
|
|
||||||
if (relevant) {
|
|
||||||
proxy.web(req, res);
|
proxy.web(req, res);
|
||||||
} else {
|
} else {
|
||||||
next();
|
next();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
, ws: function (req, socket, head, next) {
|
, ws: function (req, socket, head, next) {
|
||||||
var hostname = req.headers.host.split(':')[0];
|
if (moduleMatchesHost(req, mod)) {
|
||||||
var relevant = mod.domains.some(function (pattern) {
|
|
||||||
return domainMatches(pattern, hostname);
|
|
||||||
});
|
|
||||||
|
|
||||||
if (relevant) {
|
|
||||||
proxy.ws(req, socket, head);
|
proxy.ws(req, socket, head);
|
||||||
} else {
|
} else {
|
||||||
next();
|
next();
|
||||||
|
@ -141,6 +140,36 @@ module.exports.create = function (deps, conf, greenlockMiddleware) {
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function createRedirectRoute(mod) {
|
||||||
|
// Escape any characters that (can) have special meaning in regular expression
|
||||||
|
// but that aren't the special characters we have interest in.
|
||||||
|
var from = mod.from.replace(/[-\/\\^$+?.()|[\]{}]/g, '\\$&');
|
||||||
|
// Then modify the characters we are interested in so they do what we want in
|
||||||
|
// the regular expression after being compiled.
|
||||||
|
from = from.replace(/\*/g, '(.*)');
|
||||||
|
var fromRe = new RegExp('^' + from + '/?$');
|
||||||
|
|
||||||
|
return function (req, res, next) {
|
||||||
|
if (!moduleMatchesHost(req, mod)) {
|
||||||
|
next();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
var match = fromRe.exec(req.url);
|
||||||
|
if (!match) {
|
||||||
|
next();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
var to = mod.to;
|
||||||
|
match.slice(1).forEach(function (globMatch, index) {
|
||||||
|
to = to.replace(':'+(index+1), globMatch);
|
||||||
|
});
|
||||||
|
res.writeHead(mod.status, { 'Location': to });
|
||||||
|
res.end();
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
function createStaticRoute(mod) {
|
function createStaticRoute(mod) {
|
||||||
var getStaticApp, staticApp;
|
var getStaticApp, staticApp;
|
||||||
if (/:hostname/.test(mod.root)) {
|
if (/:hostname/.test(mod.root)) {
|
||||||
|
@ -160,13 +189,8 @@ module.exports.create = function (deps, conf, greenlockMiddleware) {
|
||||||
}
|
}
|
||||||
|
|
||||||
return function (req, res, next) {
|
return function (req, res, next) {
|
||||||
var hostname = req.headers.host.split(':')[0];
|
if (moduleMatchesHost(req, mod)) {
|
||||||
var relevant = mod.domains.some(function (pattern) {
|
getStaticApp(separatePort(req.headers.host).host)(req, res, next);
|
||||||
return domainMatches(pattern, hostname);
|
|
||||||
});
|
|
||||||
|
|
||||||
if (relevant) {
|
|
||||||
getStaticApp(hostname)(req, res, next);
|
|
||||||
} else {
|
} else {
|
||||||
next();
|
next();
|
||||||
}
|
}
|
||||||
|
@ -183,6 +207,9 @@ module.exports.create = function (deps, conf, greenlockMiddleware) {
|
||||||
proxyRoutes.push(proxyRoute);
|
proxyRoutes.push(proxyRoute);
|
||||||
app.use(proxyRoute.web);
|
app.use(proxyRoute.web);
|
||||||
}
|
}
|
||||||
|
else if (mod.name === 'redirect') {
|
||||||
|
app.use(createRedirectRoute(mod));
|
||||||
|
}
|
||||||
else if (mod.name === 'static') {
|
else if (mod.name === 'static') {
|
||||||
app.use(createStaticRoute(mod));
|
app.use(createStaticRoute(mod));
|
||||||
}
|
}
|
||||||
|
|
|
@ -5,7 +5,7 @@ module.exports.create = function (deps, config, netHandler) {
|
||||||
var parseSni = require('sni');
|
var parseSni = require('sni');
|
||||||
var greenlock = require('greenlock');
|
var greenlock = require('greenlock');
|
||||||
var localhostCerts = require('localhost.daplie.me-certificates');
|
var localhostCerts = require('localhost.daplie.me-certificates');
|
||||||
var domainMatches = require('../match-domain').match;
|
var domainMatches = require('../domain-utils').match;
|
||||||
|
|
||||||
function extractSocketProp(socket, propName) {
|
function extractSocketProp(socket, propName) {
|
||||||
// remoteAddress, remotePort... ugh... https://github.com/nodejs/node/issues/8854
|
// remoteAddress, remotePort... ugh... https://github.com/nodejs/node/issues/8854
|
||||||
|
|
Loading…
Reference in New Issue