fix: replace stripRelayHeaders with filterHeaders and add BLOCKED_HEADERS set

This commit is contained in:
MythEclipse
2026-05-07 21:16:31 +07:00
parent f2ebba51bb
commit f3ec82cbbf
3 changed files with 87 additions and 33 deletions
+2 -2
View File
@@ -2,7 +2,7 @@ import {
buildRelayRequest, buildRelayRequest,
createRelayResponse, createRelayResponse,
normalizeTargetUrl, normalizeTargetUrl,
stripRelayHeaders, filterHeaders,
isAllowedTarget, isAllowedTarget,
} from "@/lib/relay-utils"; } from "@/lib/relay-utils";
@@ -50,7 +50,7 @@ async function handler(req: Request): Promise<Response> {
); );
} }
const headers = stripRelayHeaders(new Headers(req.headers)); const headers = filterHeaders(new Headers(req.headers));
const fetchOptions = buildRelayRequest(req, targetUrl, headers); const fetchOptions = buildRelayRequest(req, targetUrl, headers);
const response = await fetch(targetUrl, fetchOptions); const response = await fetch(targetUrl, fetchOptions);
+80 -31
View File
@@ -1,49 +1,98 @@
export interface RelayOptions { export const ALLOWED_HEADERS = new Set([
stripHeaders?: string[]; "content-type",
} "accept",
"accept-encoding",
"accept-language",
"user-agent",
"referer",
"origin",
"authorization",
"proxy-authorization",
"cache-control",
]);
export const BLOCKED_HEADERS = new Set([
"x-vercel-id",
"x-vercel-deployment-url",
"x-vercel-oidc-token",
"x-vercel-oidc-token-ts",
"x-vercel-signature",
"x-vercel-edgified",
"x-vercel-ip-city",
"x-vercel-ip-country",
"x-vercel-ip-country-region",
"x-vercel-ip-latency",
"x-vercel-deployment-config",
"x-vercel-rewritten-query",
"cf-ray",
"cf-connecting-ip",
"cf-ipcountry",
"cf-ray-id",
"x-forwarded-for",
"x-forwarded-host",
"x-forwarded-proto",
"forwarded",
"cookie",
"set-cookie",
"x-real-ip",
"x-cluster-client-ip",
"x-api-key",
"x-cache",
]);
const INTERNAL_HEADERS = new Set(["x-relay-target", "x-relay-path", "host"]);
export function normalizeTargetUrl(target: string | null, relayPath: string): string | null { export function normalizeTargetUrl(target: string | null, relayPath: string): string | null {
if (!target) return null; if (!target) return null;
return target.replace(/\/$/, "") + relayPath; return target.replace(/\/$/, "") + relayPath;
} }
export function stripRelayHeaders(headers: Headers): Headers { export function filterHeaders(headers: Headers): Headers {
const stripped = new Headers(headers); const filtered = new Headers();
stripped.delete("x-relay-target"); for (const [key, value] of headers.entries()) {
stripped.delete("x-relay-path"); const lowerKey = key.toLowerCase();
stripped.delete("host"); if (INTERNAL_HEADERS.has(lowerKey)) continue;
return stripped; if (BLOCKED_HEADERS.has(lowerKey)) continue;
if (lowerKey.startsWith("x-vercel-")) continue;
if (lowerKey.startsWith("cf-")) continue;
if (lowerKey.startsWith("x-forwarded-")) continue;
// Forward remaining headers
filtered.set(key, value);
}
return filtered;
} }
export function shouldSendBody(method: string): boolean { export function shouldSendBody(method: string): boolean {
return method !== "GET" && method !== "HEAD"; return method !== "GET" && method !== "HEAD";
} }
export function buildRelayRequest( export function buildRelayRequest(
req: Request, req: Request,
targetUrl: string, targetUrl: string,
headers: Headers headers: Headers
): RequestInit { ): RequestInit {
return { return {
method: req.method, method: req.method,
headers, headers,
body: shouldSendBody(req.method) ? req.body : undefined, body: shouldSendBody(req.method) ? req.body : undefined,
duplex: "half", duplex: "half",
} as any; } as any;
} }
export function isAllowedTarget(url: string): boolean { export function isAllowedTarget(url: string): boolean {
try { try {
const parsed = new URL(url); const parsed = new URL(url);
return ["http:", "https:"].includes(parsed.protocol); return ["http:", "https:"].includes(parsed.protocol);
} catch { } catch {
return false; return false;
} }
} }
export function createRelayResponse(response: Response): Response { export function createRelayResponse(response: Response): Response {
return new Response(response.body, { const headers = new Headers(response.headers);
status: response.status, // Ensure CORS for our test page if needed, but usually we just forward
headers: response.headers, return new Response(response.body, {
}); status: response.status,
headers,
});
} }
+5
View File
@@ -0,0 +1,5 @@
{
"$schema": "https://openapi.vercel.sh/vercel.json",
"bunVersion": "1",
"installCommand": "bun install"
}