From 06e32679a47ebda0b0163e886390b12084605d10 Mon Sep 17 00:00:00 2001 From: Akos Olasz Date: Mon, 28 Nov 2022 14:02:26 +0100 Subject: [PATCH] use typescript; clean up & add test; --- .vscode/settings.json | 3 +- .../{redirects.js => redirects.ts} | 70 +++++++++++-------- netlify/test/bot-requests.ts | 68 ++++++++++++++++++ 3 files changed, 111 insertions(+), 30 deletions(-) rename netlify/edge-functions/{redirects.js => redirects.ts} (57%) create mode 100644 netlify/test/bot-requests.ts diff --git a/.vscode/settings.json b/.vscode/settings.json index c82ed27b4d..58ef607400 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -19,5 +19,6 @@ "scheme": "file" } ], - "cSpell.enabled": true + "cSpell.enabled": true, + "deno.enablePaths": ["./netlify/edge-functions", "./netlify/test"] } diff --git a/netlify/edge-functions/redirects.js b/netlify/edge-functions/redirects.ts similarity index 57% rename from netlify/edge-functions/redirects.js rename to netlify/edge-functions/redirects.ts index 1b7fa1edcf..50fb789d63 100644 --- a/netlify/edge-functions/redirects.js +++ b/netlify/edge-functions/redirects.ts @@ -1,7 +1,10 @@ -import isbot from "https://esm.sh/isbot"; +import isbot from "https://esm.sh/isbot@3.6.5"; +import { Context } from "https://edge.netlify.com/"; + +type RedirectRule = [from: string, to: string, status: number]; // prettier-ignore -const redirects = [ +const redirects: RedirectRule[] = [ [`/install.sh`, `https://download.dfinity.systems/sdk/install.sh`, 302], [`/manifest.json`, `https://download.dfinity.systems/sdk/manifest.json`, 302], [`/sdk-license-agreement.txt`, `https://download.dfinity.systems/sdk/sdk-license-agreement.txt`, 302], @@ -14,47 +17,56 @@ const redirects = [ [`/eula-storage`,`https://association.internetcomputer.org/eula-storage`, 301], ]; -export default async (request, context) => { +export function matchRedirect( + redirect: RedirectRule, + pathName: string +): string | false { + if (redirect[0].endsWith("/*")) { + // mass redirect + if (pathName.startsWith(redirect[0].slice(0, -1))) { + if (redirect[1].endsWith(":splat")) { + // splat + const destRoot = redirect[1].slice(0, -6); + const dest = destRoot + pathName.replace(redirect[0].slice(0, -1), ""); + console.log(`Splat redirect '${pathName}'=>'${dest}'`); + return dest; + } else { + // redirect to single URL + console.log(`Mass redirect '${pathName}'=>'${redirect[1]}'`); + return redirect[1]; + } + } + } else { + // single redirect + if (redirect[0] === pathName) { + console.log(`Single redirect '${pathName}'=>'${redirect[1]}'`); + return redirect[1]; + } + } + return false; +} + +export default async (request: Request, context: Context) => { const url = new URL(request.url); // check if request needs to be redirected for (const redirect of redirects) { - if (redirect[0].endsWith("/*")) { - // mass redirect - if (url.pathname.startsWith(redirect[0].slice(0, -1))) { - if (redirect[1].endsWith(":splat")) { - // splat - const destRoot = redirect[1].slice(0, -6); - const dest = - destRoot + url.pathname.replace(redirect[0].slice(0, -1), ""); - console.log(`Splat redirect '${url.pathname}'=>'${dest}'`); - return Response.redirect(dest, redirect[2]); - } else { - // redirect to single URL - console.log(`Mass redirect '${url.pathname}'=>'${redirect[1]}'`); - return Response.redirect(redirect[1], redirect[2]); - } - } - } else { - // single redirect - if (redirect[0] === url.pathname) { - console.log(`Single redirect '${url.pathname}'=>'${redirect[1]}'`); - return Response.redirect(redirect[1], redirect[2]); - } + const maybeDesitinationUrl = matchRedirect(redirect, url.pathname); + if (maybeDesitinationUrl !== false) { + return Response.redirect(maybeDesitinationUrl, redirect[2]); } } if ( url.hostname === "internetcomputer.org" || - url.hostname === "deploy-preview-856--icportal.netlify.app" + url.hostname === "deploy-preview-856--icportal.netlify.app" // add this for testing, TODO: remove ) { // production hostname, this has service worker deployed // check if it's bot user => proxy content from .raw as response - const requestHeaders = Object.fromEntries(request.headers); - const isBotRequest = isbot(requestHeaders["user-agent"]); + const userAgent = request.headers.get("user-agent"); - if (isBotRequest) { + if (userAgent !== null && isbot(userAgent)) { const newRequest = new Request( request.url.replace( url.hostname, diff --git a/netlify/test/bot-requests.ts b/netlify/test/bot-requests.ts new file mode 100644 index 0000000000..19ebef0e19 --- /dev/null +++ b/netlify/test/bot-requests.ts @@ -0,0 +1,68 @@ +import { assertEquals } from "https://deno.land/std@0.166.0/testing/asserts.ts"; +import { matchRedirect } from "../edge-functions/redirects.ts"; + +Deno.test("matchRedirect tests", () => { + // bulk to single URL + assertEquals(matchRedirect(["/*", "/hello", 301], "/test-url"), "/hello"); + assertEquals(matchRedirect(["/*", "/", 301], "/test-url"), "/"); + + // bulk splat + assertEquals( + matchRedirect( + ["/downloads/*", "https://download.dfinity.systems/sdk/:splat", 302], + "/downloads/test-file.txt" + ), + "https://download.dfinity.systems/sdk/test-file.txt" + ); + + assertEquals( + matchRedirect( + ["/downloads/*", "https://download.dfinity.systems/sdk/:splat", 302], + "/downloads/subdir/test-file.txt" + ), + "https://download.dfinity.systems/sdk/subdir/test-file.txt" + ); + + assertEquals( + matchRedirect(["/*", "/docs/:splat", 302], "/hello/test-file.txt"), + "/docs/hello/test-file.txt" + ); + + // single URL redirect + assertEquals( + matchRedirect( + ["/install.sh", "https://download.dfinity.systems/sdk/install.sh", 302], + "/install.sh" + ), + "https://download.dfinity.systems/sdk/install.sh" + ); + assertEquals( + matchRedirect( + ["/eula", "https://association.internetcomputer.org/eula", 302], + "/eula" + ), + "https://association.internetcomputer.org/eula" + ); + assertEquals( + matchRedirect( + [ + "/eula-storage", + "https://association.internetcomputer.org/eula-storage", + 302, + ], + "/eula-storage" + ), + "https://association.internetcomputer.org/eula-storage" + ); + assertEquals( + matchRedirect( + [ + "/eula-storage", + "https://association.internetcomputer.org/eula-storage", + 302, + ], + "/eula-storage/123" + ), + false + ); +});