From e3234bce6c5adc6913c0851b5f635a0f9f58d093 Mon Sep 17 00:00:00 2001 From: Jesse Houwing Date: Mon, 24 Sep 2018 18:57:05 +0200 Subject: [PATCH] =?UTF-8?q?=F0=9F=8E=A8Added=20case=20insensitive=20suppor?= =?UTF-8?q?t=20for=20redirects=20(#9755)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit no issue - e.g. "/^\\/case-insensitive/i - Adds tests for case sensitive redirects - Needs a doc update on release! --- .../shared/middlewares/custom-redirects.js | 15 +++++- .../functional/routes/api/redirects_spec.js | 2 +- core/test/functional/routes/frontend_spec.js | 48 +++++++++++++++++++ core/test/utils/fixtures/data/redirects.json | 11 +++++ 4 files changed, 73 insertions(+), 3 deletions(-) diff --git a/core/server/web/shared/middlewares/custom-redirects.js b/core/server/web/shared/middlewares/custom-redirects.js index 4ae25a5967..b6e11aa82c 100644 --- a/core/server/web/shared/middlewares/custom-redirects.js +++ b/core/server/web/shared/middlewares/custom-redirects.js @@ -22,12 +22,23 @@ _private.registerRoutes = () => { validation.validateRedirects(redirects); redirects.forEach((redirect) => { + /** + * Detect case insensitive modifier when regex is enclosed by + * / ... /i + */ + let options = ''; + if (redirect.from.match(/^\/.*\/i$/)) { + redirect.from = redirect.from.slice(1, -2); + options = 'i'; + } + /** * always delete trailing slashes, doesn't matter if regex or not * Example: * - you define /my-blog-post-1/ as from property * - /my-blog-post-1 or /my-blog-post-1/ should work */ + if (redirect.from.match(/\/$/)) { redirect.from = redirect.from.slice(0, -1); } @@ -37,7 +48,7 @@ _private.registerRoutes = () => { } debug('register', redirect.from); - customRedirectsRouter.get(new RegExp(redirect.from), function customRedirect(req, res) { + customRedirectsRouter.get(new RegExp(redirect.from, options), function (req, res) { const maxAge = redirect.permanent ? config.get('caching:customRedirects:maxAge') : 0, parsedUrl = url.parse(req.originalUrl); @@ -46,7 +57,7 @@ _private.registerRoutes = () => { }); res.redirect(redirect.permanent ? 301 : 302, url.format({ - pathname: parsedUrl.pathname.replace(new RegExp(redirect.from), redirect.to), + pathname: parsedUrl.pathname.replace(new RegExp(redirect.from, options), redirect.to), search: parsedUrl.search })); }); diff --git a/core/test/functional/routes/api/redirects_spec.js b/core/test/functional/routes/api/redirects_spec.js index 1e9255a632..8d2a0b4c51 100644 --- a/core/test/functional/routes/api/redirects_spec.js +++ b/core/test/functional/routes/api/redirects_spec.js @@ -73,7 +73,7 @@ describe('Redirects API', function () { res.headers['content-disposition'].should.eql('Attachment; filename="redirects.json"'); res.headers['content-type'].should.eql('application/json; charset=utf-8'); - res.headers['content-length'].should.eql('463'); + res.headers['content-length'].should.eql('648'); done(); }); diff --git a/core/test/functional/routes/frontend_spec.js b/core/test/functional/routes/frontend_spec.js index 2c658d463c..630586e7f4 100644 --- a/core/test/functional/routes/frontend_spec.js +++ b/core/test/functional/routes/frontend_spec.js @@ -715,6 +715,36 @@ describe('Frontend Routing', function () { }); }); + it('with case insensitive', function (done) { + request.get('/CaSe-InSeNsItIvE') + .expect(302) + .expect('Cache-Control', testUtils.cacheRules.public) + .end(function (err, res) { + res.headers.location.should.eql('/redirected-insensitive'); + doEnd(done)(err, res); + }); + }); + + it('with case sensitive', function (done) { + request.get('/Case-Sensitive') + .expect(302) + .expect('Cache-Control', testUtils.cacheRules.public) + .end(function (err, res) { + res.headers.location.should.eql('/redirected-sensitive'); + doEnd(done)(err, res); + }); + }); + + it('defaults to case sensitive', function (done) { + request.get('/Default-Sensitive') + .expect(302) + .expect('Cache-Control', testUtils.cacheRules.public) + .end(function (err, res) { + res.headers.location.should.eql('/redirected-default'); + doEnd(done)(err, res); + }); + }); + it('should not redirect', function (done) { request.get('/post/a-nice-blog-post/') .end(function (err, res) { @@ -723,6 +753,24 @@ describe('Frontend Routing', function () { doEnd(done)(err, res); }); }); + + it('should not redirect with case sensitive', function (done) { + request.get('/casE-sensitivE') + .end(function (err, res) { + res.headers.location.should.not.eql('/redirected-sensitive'); + res.statusCode.should.not.eql(302); + doEnd(done)(err, res); + }); + }); + + it('should not redirect with default case sensitive', function (done) { + request.get('/defaulT-sensitivE') + .end(function (err, res) { + res.headers.location.should.not.eql('/redirected-default'); + res.statusCode.should.not.eql(302); + doEnd(done)(err, res); + }); + }); }); describe('2 case', function () { diff --git a/core/test/utils/fixtures/data/redirects.json b/core/test/utils/fixtures/data/redirects.json index ad471fdf99..ace3c1358a 100644 --- a/core/test/utils/fixtures/data/redirects.json +++ b/core/test/utils/fixtures/data/redirects.json @@ -31,5 +31,16 @@ { "from": "^/prefix/([a-z0-9\\-]+)?", "to": "/blog/$1" + }, + { + "from": "/^\\/case-insensitive/i", + "to": "/redirected-insensitive" + },{ + "from": "^\\/Case-Sensitive", + "to": "/redirected-sensitive" + }, + { + "from": "^\\/Default-Sensitive", + "to": "/redirected-default" } ]