forked from coolaj86/goldilocks.js
		
	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) {
 | 
			
		||||
          // 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');
 | 
			
		||||
          Object.keys(failed).forEach(function (key) {
 | 
			
		||||
            console.log('[error bind]', key, failed[key].code);
 | 
			
		||||
 | 
			
		||||
@ -22,6 +22,12 @@ http:
 | 
			
		||||
  allow_insecure: false
 | 
			
		||||
  primary_domain: localhost.foo.daplie.me
 | 
			
		||||
  modules:
 | 
			
		||||
    - name: redirect
 | 
			
		||||
      domains:
 | 
			
		||||
        - localhost.beta.daplie.me
 | 
			
		||||
      status: 301
 | 
			
		||||
      from: /old/path/*/other/*
 | 
			
		||||
      to: /path/new/:2/something/:1
 | 
			
		||||
    - name: proxy
 | 
			
		||||
      domains:
 | 
			
		||||
        - localhost.daplie.me
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										30
									
								
								lib/domain-utils.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										30
									
								
								lib/domain-utils.js
									
									
									
									
									
										Normal file
									
								
							@ -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 app = express();
 | 
			
		||||
  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 adminDomains = [
 | 
			
		||||
@ -14,8 +15,16 @@ module.exports.create = function (deps, conf, greenlockMiddleware) {
 | 
			
		||||
  , /\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) {
 | 
			
		||||
    var host = /^(.*?)(:\d+)?$/.exec(fullHost)[1];
 | 
			
		||||
    var host = separatePort(fullHost).host;
 | 
			
		||||
 | 
			
		||||
    if (host === 'localhost') {
 | 
			
		||||
      return fullHost.replace(host, 'localhost.daplie.me');
 | 
			
		||||
@ -50,7 +59,7 @@ module.exports.create = function (deps, conf, greenlockMiddleware) {
 | 
			
		||||
      return;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    var port = (/:(\d+)$/.exec(req.headers.host) || [])[1];
 | 
			
		||||
    var port = separatePort(req.headers.host).port;
 | 
			
		||||
    if (!redirecters[port]) {
 | 
			
		||||
      redirecters[port] = require('redirect-https')({
 | 
			
		||||
        port: port
 | 
			
		||||
@ -115,24 +124,14 @@ module.exports.create = function (deps, conf, greenlockMiddleware) {
 | 
			
		||||
 | 
			
		||||
    return {
 | 
			
		||||
      web: function (req, res, next) {
 | 
			
		||||
        var hostname = req.headers.host.split(':')[0];
 | 
			
		||||
        var relevant = mod.domains.some(function (pattern) {
 | 
			
		||||
          return domainMatches(pattern, hostname);
 | 
			
		||||
        });
 | 
			
		||||
 | 
			
		||||
        if (relevant) {
 | 
			
		||||
        if (moduleMatchesHost(req, mod)) {
 | 
			
		||||
          proxy.web(req, res);
 | 
			
		||||
        } else {
 | 
			
		||||
          next();
 | 
			
		||||
        }
 | 
			
		||||
      }
 | 
			
		||||
    , ws: function (req, socket, head, next) {
 | 
			
		||||
        var hostname = req.headers.host.split(':')[0];
 | 
			
		||||
        var relevant = mod.domains.some(function (pattern) {
 | 
			
		||||
          return domainMatches(pattern, hostname);
 | 
			
		||||
        });
 | 
			
		||||
 | 
			
		||||
        if (relevant) {
 | 
			
		||||
        if (moduleMatchesHost(req, mod)) {
 | 
			
		||||
          proxy.ws(req, socket, head);
 | 
			
		||||
        } else {
 | 
			
		||||
          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) {
 | 
			
		||||
    var getStaticApp, staticApp;
 | 
			
		||||
    if (/:hostname/.test(mod.root)) {
 | 
			
		||||
@ -160,13 +189,8 @@ module.exports.create = function (deps, conf, greenlockMiddleware) {
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    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);
 | 
			
		||||
      if (moduleMatchesHost(req, mod)) {
 | 
			
		||||
        getStaticApp(separatePort(req.headers.host).host)(req, res, next);
 | 
			
		||||
      } else {
 | 
			
		||||
        next();
 | 
			
		||||
      }
 | 
			
		||||
@ -183,6 +207,9 @@ module.exports.create = function (deps, conf, greenlockMiddleware) {
 | 
			
		||||
      proxyRoutes.push(proxyRoute);
 | 
			
		||||
      app.use(proxyRoute.web);
 | 
			
		||||
    }
 | 
			
		||||
    else if (mod.name === 'redirect') {
 | 
			
		||||
      app.use(createRedirectRoute(mod));
 | 
			
		||||
    }
 | 
			
		||||
    else if (mod.name === 'static') {
 | 
			
		||||
      app.use(createStaticRoute(mod));
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
@ -5,7 +5,7 @@ module.exports.create = function (deps, config, netHandler) {
 | 
			
		||||
  var parseSni = require('sni');
 | 
			
		||||
  var greenlock = require('greenlock');
 | 
			
		||||
  var localhostCerts = require('localhost.daplie.me-certificates');
 | 
			
		||||
  var domainMatches = require('../match-domain').match;
 | 
			
		||||
  var domainMatches = require('../domain-utils').match;
 | 
			
		||||
 | 
			
		||||
  function extractSocketProp(socket, propName) {
 | 
			
		||||
    // remoteAddress, remotePort... ugh... https://github.com/nodejs/node/issues/8854
 | 
			
		||||
 | 
			
		||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user