From ea60931efab8e3257dc92f48e36962d0a3e60010 Mon Sep 17 00:00:00 2001
From: Joannic Laborde <joannic@sparkart.com>
Date: Mon, 6 Nov 2017 10:16:22 -0400
Subject: [PATCH 1/7] Add support for redirecting the protocol and host

---
 lib/redirect.js                   | 71 ++++++++++++++++---------------
 test/fixtures/site 1/redirects.js | 36 +++++++++++++++-
 test/solidus.js                   | 20 +++++++++
 3 files changed, 92 insertions(+), 35 deletions(-)

diff --git a/lib/redirect.js b/lib/redirect.js
index 16e03f6..315893c 100644
--- a/lib/redirect.js
+++ b/lib/redirect.js
@@ -7,55 +7,58 @@ var moment = require('moment');
 
 var utils = require('./utils.js');
 
-var Redirect = function( redirect_data, options ){
-
+var Redirect = function(redirect_data, options) {
   options = options || {};
 
   var redirect = this;
-  var server = options.server;
-  var router = server.router;
+  var router = options.server.router;
   var status = redirect_data.permanent ? PERMANENT_STATUS : TEMPORARY_STATUS;
   var start = redirect_data.start;
   var end = redirect_data.end;
-  var from = redirect_data.from;
-  var to = redirect_data.to;
-  var expired = ( moment() > moment( end ) );
-
-  // don't create redirect route at all if expired
-  // don't check prematurity yet since it could become valid later
-  if( !expired ){
-
-    if (from instanceof RegExp) {
-      this.route = from;
-    } else {
-      this.route = path.normalize( from ).replace( /\\/g, '/' );
-      this.route = utils.formatRouteForExpress(this.route);
+  var from = _.isObject(redirect_data.from) && !_.isRegExp(redirect_data.from) ? redirect_data.from : {path: redirect_data.from};
+  var to = _.isObject(redirect_data.to) && !_.isFunction(redirect_data.to) ? redirect_data.to : {url: redirect_data.to};
+  var expired = moment() > moment(end);
+
+  // Don't create redirect route at all if expired
+  // Don't check prematurity yet since it could become valid later
+  if (!expired) {
+    redirect.route = from.path || '*';
+    if (_.isString(redirect.route)) {
+      redirect.route = path.normalize(redirect.route).replace(/\\/g, '/');
+      redirect.route = utils.formatRouteForExpress(redirect.route);
     }
 
-    router.get( this.route, function( req, res, next ){
-      var expired = ( moment() > moment( end ) );
-      var premature = ( moment() < moment( start ) );
-      // if redirect is expired or premature skip it
-      if( !expired && !premature ){
-        var url = typeof(to) == 'function' ? to(req.params) : to;
-        res.redirect( status, utils.expandVariables(url, req.params) );
-      }
-      else {
-        next();
+    router.get(redirect.route, function(req, res, next) {
+      // If redirect is expired or premature skip it
+      var expired = moment() > moment(end);
+      var premature = moment() < moment(start);
+      if (expired || premature) return next();
+
+      // If the protocol or host don't match, skip redirect
+      if (from.protocol && from.protocol !== req.protocol) return next();
+      if (from.host && from.host !== req.host) return next();
+
+      // Compute to
+      var newTo = to;
+      if (_.isFunction(newTo.url)) {
+        newTo = newTo.url(req.params);
+        if (!_.isObject(newTo)) newTo = Object.assign({}, to, {url: newTo});
       }
-    });
 
-    // removes the redirect route
-    this.destroy = function(){
+      // Compute location
+      var location = newTo.protocol || newTo.host ? `${newTo.protocol || req.protocol}://${newTo.host || req.host}` : '';
+      location += newTo.url ? utils.expandVariables(newTo.url, req.params) : req.url;
 
-      router.routes.get = _( router.routes.get ).reject( function( current_route ){
+      res.redirect(status, location);
+    });
+
+    // Removes the redirect route
+    this.destroy = function() {
+      router.routes.get = _(router.routes.get).reject(function(current_route) {
         return redirect.route === current_route.path;
       });
-
     };
-
   }
-
 };
 
 module.exports = Redirect;
\ No newline at end of file
diff --git a/test/fixtures/site 1/redirects.js b/test/fixtures/site 1/redirects.js
index 9694192..5fc3843 100644
--- a/test/fixtures/site 1/redirects.js	
+++ b/test/fixtures/site 1/redirects.js	
@@ -34,4 +34,38 @@ module.exports = [
   to: function(params) {
     return "/new/{1}/{0}/" + (1000 + parseInt(params['2']));
   }
-}];
\ No newline at end of file
+}, {
+  from: {
+    protocol: 'http',
+    host: 'solidusjs.com',
+    path: '/match-http-root'
+  },
+  to: '/new/match-http-root'
+}, {
+  from: {
+    protocol: 'https',
+    host: 'solidusjs.com',
+    path: '/match-https-root'
+  },
+  to: '/new/match-https-root'
+}, {
+  from: {
+    host: 'no-path.com'
+  },
+  to: {
+    host: 'www.no-path.com'
+  }
+}, {
+  from: '/to-https-www',
+  to: {
+    protocol: 'https',
+    host: 'www.solidusjs.com'
+  }
+}, {
+  from: '/to-https-www-url/{dynamic}',
+  to: {
+    protocol: 'https',
+    host: 'www.solidusjs.com',
+    url: '/new/url/{dynamic}'
+  }
+}];
diff --git a/test/solidus.js b/test/solidus.js
index a2e687c..24cbc91 100644
--- a/test/solidus.js
+++ b/test/solidus.js
@@ -583,6 +583,26 @@ describe( 'Solidus', function(){
         function( callback ){
           s_request.get('/redirect9/12-34-56-78').expect( 'location', '/new/56/12/1078', callback );
         },
+        function( callback ){
+          s_request.get('/match-http-root?with=params').set('Host', 'solidusjs.com').expect( 'location', '/new/match-http-root', callback );
+        },
+        function( callback ){
+          // Bad protocol
+          s_request.get('/match-https-root?with=params').set('Host', 'solidusjs.com').expect( 404, callback );
+        },
+        function( callback ){
+          // Bad host
+          s_request.get('/match-http-root?with=params').set('Host', 'www.solidusjs.com').expect( 404, callback );
+        },
+        function( callback ){
+          s_request.get('/some/path?with=params').set('Host', 'no-path.com').expect( 'location', 'http://www.no-path.com/some/path?with=params', callback );
+        },
+        function( callback ){
+          s_request.get('/to-https-www?with=params').set('Host', 'solidusjs.com').expect( 'location', 'https://www.solidusjs.com/to-https-www?with=params', callback );
+        },
+        function( callback ){
+          s_request.get('/to-https-www-url/old-path?with=params').set('Host', 'solidusjs.com').expect( 'location', 'https://www.solidusjs.com/new/url/old-path', callback );
+        },
         function( callback ){
           s_request.get('/past-redirect').expect( 404, callback );
         },

From 4786f4d540c8974cedbb4a84e6546cf1aee07142 Mon Sep 17 00:00:00 2001
From: Joannic Laborde <joannic@sparkart.com>
Date: Mon, 6 Nov 2017 10:49:47 -0400
Subject: [PATCH 2/7] =?UTF-8?q?Use=20old=20node=E2=80=A6?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

---
 lib/redirect.js | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)

diff --git a/lib/redirect.js b/lib/redirect.js
index 315893c..b5fc6d1 100644
--- a/lib/redirect.js
+++ b/lib/redirect.js
@@ -29,6 +29,7 @@ var Redirect = function(redirect_data, options) {
     }
 
     router.get(redirect.route, function(req, res, next) {
+console.log(from, to, req.protocol, req.host, req.url);
       // If redirect is expired or premature skip it
       var expired = moment() > moment(end);
       var premature = moment() < moment(start);
@@ -46,7 +47,7 @@ var Redirect = function(redirect_data, options) {
       }
 
       // Compute location
-      var location = newTo.protocol || newTo.host ? `${newTo.protocol || req.protocol}://${newTo.host || req.host}` : '';
+      var location = newTo.protocol || newTo.host ? ((newTo.protocol || req.protocol) + '://' + (newTo.host || req.host)) : '';
       location += newTo.url ? utils.expandVariables(newTo.url, req.params) : req.url;
 
       res.redirect(status, location);

From 143d004664ceefcbc1671f674d50efabf9e0b784 Mon Sep 17 00:00:00 2001
From: Joannic Laborde <joannic@sparkart.com>
Date: Mon, 6 Nov 2017 13:11:02 -0400
Subject: [PATCH 3/7] trust proxy

---
 lib/server.js | 1 +
 package.json  | 2 +-
 2 files changed, 2 insertions(+), 1 deletion(-)

diff --git a/lib/server.js b/lib/server.js
index 47e94c9..d3a6e5b 100644
--- a/lib/server.js
+++ b/lib/server.js
@@ -116,6 +116,7 @@ var SolidusServer = function( options ){
   router.engine( DEFAULT_VIEW_EXTENSION, handlebars.engine );
   router.set( 'view engine', DEFAULT_VIEW_EXTENSION );
   router.set( 'views', paths.views );
+  router.set( 'trust proxy', true );
   router.use( express.compress() );
   router.use(function(req, res, next) {
     res.set({'X-Powered-By': 'Solidus/' + VERSION});
diff --git a/package.json b/package.json
index 3c6c428..8b6ee40 100644
--- a/package.json
+++ b/package.json
@@ -23,7 +23,7 @@
     "commander": "1.1.x",
     "continuation-local-storage": "~3.1.1",
     "express": "3.1.x",
-    "express-expose": "SparkartGroupInc/express-expose#escape-script-ending-tag",
+    "express-expose": "sparkartgroupinc/express-expose#escape-script-ending-tag",
     "express-handlebars": "1.2.2",
     "glob": "~3.2.6",
     "handlebars": "^1.3.0",

From 1c7a2084eb4eea308d32e3a507b6e4cb7a62f41b Mon Sep 17 00:00:00 2001
From: Joannic Laborde <joannic@sparkart.com>
Date: Mon, 6 Nov 2017 13:55:24 -0400
Subject: [PATCH 4/7] Update CircleCI Node and NPM versions

---
 circle.yml      | 8 +++-----
 lib/redirect.js | 1 -
 2 files changed, 3 insertions(+), 6 deletions(-)

diff --git a/circle.yml b/circle.yml
index 1961311..fa0613d 100644
--- a/circle.yml
+++ b/circle.yml
@@ -1,7 +1,5 @@
 machine:
   node:
-    version: v4.5.0
-dependencies:
-  # https://discuss.circleci.com/t/testing-multiple-versions-of-node/542
-  pre:
-    - case $CIRCLE_NODE_INDEX in 0) NODE_VERSION=0.12 ;; 1) NODE_VERSION=4 ;; esac; nvm install $NODE_VERSION && nvm alias default $NODE_VERSION
+    version: v4.8.4
+  npm:
+    version: v2.15.11
diff --git a/lib/redirect.js b/lib/redirect.js
index b5fc6d1..58411ea 100644
--- a/lib/redirect.js
+++ b/lib/redirect.js
@@ -29,7 +29,6 @@ var Redirect = function(redirect_data, options) {
     }
 
     router.get(redirect.route, function(req, res, next) {
-console.log(from, to, req.protocol, req.host, req.url);
       // If redirect is expired or premature skip it
       var expired = moment() > moment(end);
       var premature = moment() < moment(start);

From dc3616445b121bd5f13c995347e6eae9abbd4251 Mon Sep 17 00:00:00 2001
From: Joannic Laborde <joannic@sparkart.com>
Date: Mon, 6 Nov 2017 14:15:17 -0400
Subject: [PATCH 5/7] Comment

---
 lib/server.js | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/lib/server.js b/lib/server.js
index d3a6e5b..24c5830 100644
--- a/lib/server.js
+++ b/lib/server.js
@@ -116,7 +116,7 @@ var SolidusServer = function( options ){
   router.engine( DEFAULT_VIEW_EXTENSION, handlebars.engine );
   router.set( 'view engine', DEFAULT_VIEW_EXTENSION );
   router.set( 'views', paths.views );
-  router.set( 'trust proxy', true );
+  router.set( 'trust proxy', true ); // Use the X-Forwarded-* headers: https://expressjs.com/en/guide/behind-proxies.html
   router.use( express.compress() );
   router.use(function(req, res, next) {
     res.set({'X-Powered-By': 'Solidus/' + VERSION});

From 6ead0d3ce461dcfd8e3700b2da6ebecabe5a6491 Mon Sep 17 00:00:00 2001
From: Joannic Laborde <joannic@sparkart.com>
Date: Mon, 13 Nov 2017 09:39:14 -0400
Subject: [PATCH 6/7] Test without "trust proxy"

---
 lib/server.js | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/lib/server.js b/lib/server.js
index 24c5830..937bfb5 100644
--- a/lib/server.js
+++ b/lib/server.js
@@ -116,7 +116,7 @@ var SolidusServer = function( options ){
   router.engine( DEFAULT_VIEW_EXTENSION, handlebars.engine );
   router.set( 'view engine', DEFAULT_VIEW_EXTENSION );
   router.set( 'views', paths.views );
-  router.set( 'trust proxy', true ); // Use the X-Forwarded-* headers: https://expressjs.com/en/guide/behind-proxies.html
+  // router.set( 'trust proxy', true ); // Use the X-Forwarded-* headers: https://expressjs.com/en/guide/behind-proxies.html
   router.use( express.compress() );
   router.use(function(req, res, next) {
     res.set({'X-Powered-By': 'Solidus/' + VERSION});

From e37b2ceb5de97cd65406e563ba719593885bb80c Mon Sep 17 00:00:00 2001
From: Joannic Laborde <joannic@sparkart.com>
Date: Mon, 13 Nov 2017 09:57:26 -0400
Subject: [PATCH 7/7] "trust proxy" is required

---
 lib/server.js | 2 +-
 package.json  | 2 +-
 2 files changed, 2 insertions(+), 2 deletions(-)

diff --git a/lib/server.js b/lib/server.js
index 937bfb5..24c5830 100644
--- a/lib/server.js
+++ b/lib/server.js
@@ -116,7 +116,7 @@ var SolidusServer = function( options ){
   router.engine( DEFAULT_VIEW_EXTENSION, handlebars.engine );
   router.set( 'view engine', DEFAULT_VIEW_EXTENSION );
   router.set( 'views', paths.views );
-  // router.set( 'trust proxy', true ); // Use the X-Forwarded-* headers: https://expressjs.com/en/guide/behind-proxies.html
+  router.set( 'trust proxy', true ); // Use the X-Forwarded-* headers: https://expressjs.com/en/guide/behind-proxies.html
   router.use( express.compress() );
   router.use(function(req, res, next) {
     res.set({'X-Powered-By': 'Solidus/' + VERSION});
diff --git a/package.json b/package.json
index 8b6ee40..6c28dec 100644
--- a/package.json
+++ b/package.json
@@ -23,7 +23,7 @@
     "commander": "1.1.x",
     "continuation-local-storage": "~3.1.1",
     "express": "3.1.x",
-    "express-expose": "sparkartgroupinc/express-expose#escape-script-ending-tag",
+    "express-expose": "sparkartgroup/express-expose#escape-script-ending-tag",
     "express-handlebars": "1.2.2",
     "glob": "~3.2.6",
     "handlebars": "^1.3.0",
