From 6e8b4f30c14c7210ba18d1e5d603c051ed448a59 Mon Sep 17 00:00:00 2001 From: jj Date: Sat, 8 Feb 2025 13:53:29 +0000 Subject: [PATCH] api/url: add function for resolving shortlinks motivation: we frequently need to resolve shortlinks to full URLs let's have a common standard function for doing this safely instead of reinventing the wheel in every single service module --- api/src/misc/utils.js | 15 ++++++++------- api/src/processing/url.js | 15 +++++++++++++++ 2 files changed, 23 insertions(+), 7 deletions(-) diff --git a/api/src/misc/utils.js b/api/src/misc/utils.js index 331528d4..ffa75433 100644 --- a/api/src/misc/utils.js +++ b/api/src/misc/utils.js @@ -1,12 +1,13 @@ +import { request } from 'undici'; const redirectStatuses = new Set([301, 302, 303, 307, 308]); -export async function getRedirectingURL(url, dispatcher) { - const location = await fetch(url, { - redirect: 'manual', - dispatcher, - }).then((r) => { - if (redirectStatuses.has(r.status) && r.headers.has('location')) { - return r.headers.get('location'); +export async function getRedirectingURL(url, dispatcher, userAgent) { + const location = await request(url, { + dispatcher, method: 'HEAD', + headers: { 'user-agent': userAgent } + }).then(r => { + if (redirectStatuses.has(r.statusCode) && r.headers['location']) { + return r.headers['location']; } }).catch(() => null); diff --git a/api/src/processing/url.js b/api/src/processing/url.js index cfbbecc0..5c4035eb 100644 --- a/api/src/processing/url.js +++ b/api/src/processing/url.js @@ -4,6 +4,7 @@ import { strict as assert } from "node:assert"; import { env } from "../config.js"; import { services } from "./service-config.js"; import { friendlyServiceName } from "./service-alias.js"; +import { getRedirectingURL } from "../misc/utils.js"; function aliasURL(url) { assert(url instanceof URL); @@ -221,3 +222,17 @@ export function extract(url) { return { host, patternMatch }; } + +export async function resolveRedirectingURL(url, dispatcher, userAgent) { + const originalService = getHostIfValid(normalizeURL(url)); + if (!originalService) return; + + const canonicalURL = await getRedirectingURL(url, dispatcher, userAgent); + if (!canonicalURL) return; + + const { host, patternMatch } = extract(normalizeURL(canonicalURL)); + + if (host === originalService) { + return patternMatch; + } +}