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
This commit is contained in:
jj 2025-02-08 13:53:29 +00:00
parent 77dca70792
commit 6e8b4f30c1
No known key found for this signature in database
2 changed files with 23 additions and 7 deletions

View File

@ -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);

View File

@ -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;
}
}