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 16e03f6..58411ea 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/lib/server.js b/lib/server.js index 47e94c9..24c5830 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 ); // 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 3c6c428..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", 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 ); },