From 3ee9f54162a46391b9fcf1489db2b84854347899 Mon Sep 17 00:00:00 2001 From: Leo Lamprecht Date: Tue, 29 May 2018 12:23:11 +0200 Subject: [PATCH] Fixed rewriting behavior (#11) * Copy array when rewriting * Test for new case * Apply rewrites only if path doesn't exist on disk --- src/index.js | 44 ++++++++++++++++++++++++++------------------ test/integration.js | 18 ++++++++++++++++++ 2 files changed, 44 insertions(+), 18 deletions(-) diff --git a/src/index.js b/src/index.js index a79a4d5..e25b110 100644 --- a/src/index.js +++ b/src/index.js @@ -65,25 +65,32 @@ const toTarget = (source, destination, previousPath) => { return toPath(props); }; -const applyRewrites = (requestPath, rewrites = []) => { - if (rewrites.length === 0) { - return requestPath; +const applyRewrites = (requestPath, rewrites = [], repetitive) => { + // We need to copy the array, since we're going to modify it. + const rewritesCopy = rewrites.slice(); + + // If the method was called again, the path was already rewritten + // so we need to make sure to return it. + const fallback = repetitive ? requestPath : null; + + if (rewritesCopy.length === 0) { + return fallback; } - for (let index = 0; index < rewrites.length; index++) { + for (let index = 0; index < rewritesCopy.length; index++) { const {source, destination} = rewrites[index]; const target = toTarget(source, destination, requestPath); if (target) { // Remove rules that were already applied - rewrites.splice(index, 1); + rewritesCopy.splice(index, 1); // Check if there are remaining ones to be applied - return applyRewrites(slasher(target), rewrites); + return applyRewrites(slasher(target), rewritesCopy, true); } } - return requestPath; + return fallback; }; const shouldRedirect = (decodedPath, {redirects = [], trailingSlash}, cleanUrl) => { @@ -213,8 +220,8 @@ const getPossiblePaths = (relativePath, extension) => [ relativePath.endsWith('/') ? relativePath.replace(/\/$/g, extension) : (relativePath + extension) ]; -const findRelated = async (current, relativePath, originalStat, extension = '.html') => { - const possible = getPossiblePaths(relativePath, extension); +const findRelated = async (current, relativePath, rewrittenPath, originalStat, extension = '.html') => { + const possible = rewrittenPath ? [rewrittenPath] : getPossiblePaths(relativePath, extension); let stats = null; @@ -244,7 +251,7 @@ const findRelated = async (current, relativePath, originalStat, extension = '.ht // At this point, no `.html` files have been found, so we // need to check for the existance of `.htm` ones. - return findRelated(current, relativePath, originalStat, '.htm'); + return findRelated(current, relativePath, rewrittenPath, originalStat, '.htm'); }; const canBeListed = (excluded, file) => { @@ -388,9 +395,11 @@ module.exports = async (request, response, config = {}, methods = {}) => { const current = config.public ? path.join(cwd, config.public) : cwd; const handlers = getHandlers(methods); - const decodedPath = decodeURIComponent(url.parse(request.url).pathname); - const cleanUrl = applicable(decodedPath, config.cleanUrls); - const redirect = shouldRedirect(decodedPath, config, cleanUrl); + let relativePath = decodeURIComponent(url.parse(request.url).pathname); + let absolutePath = path.join(current, relativePath); + + const cleanUrl = applicable(relativePath, config.cleanUrls); + const redirect = shouldRedirect(relativePath, config, cleanUrl); if (redirect) { response.writeHead(redirect.statusCode, { @@ -401,9 +410,6 @@ module.exports = async (request, response, config = {}, methods = {}) => { return; } - let relativePath = applyRewrites(decodedPath, config.rewrites); - let absolutePath = path.join(current, relativePath); - let stats = null; try { @@ -417,9 +423,11 @@ module.exports = async (request, response, config = {}, methods = {}) => { } } - if ((!stats || stats.isDirectory()) && cleanUrl) { + const rewrittenPath = applyRewrites(relativePath, config.rewrites); + + if ((!stats || stats.isDirectory()) && (cleanUrl || rewrittenPath)) { try { - const related = await findRelated(current, relativePath, handlers.stat); + const related = await findRelated(current, relativePath, rewrittenPath, handlers.stat); if (related) { ({stats, absolutePath} = related); diff --git a/test/integration.js b/test/integration.js index 181b116..ebe5274 100644 --- a/test/integration.js +++ b/test/integration.js @@ -215,6 +215,24 @@ test('set `rewrites` config property to wildcard path', async t => { t.is(text, content); }); +test('set `rewrites` config property to non-matching path', async t => { + const destination = '404.html'; + const related = path.join(fixturesFull, destination); + const content = await fs.readFile(related, 'utf8'); + + const url = await getUrl({ + rewrites: [{ + source: 'face/**', + destination + }] + }); + + const response = await fetch(`${url}/mask/delete`); + const text = await response.text(); + + t.is(text, content); +}); + test('set `rewrites` config property to one-star wildcard path', async t => { const destination = '.dotfile'; const related = path.join(fixturesFull, destination);