From 9ef2c6a60e22352d14f52d78542ee1b837fc62a9 Mon Sep 17 00:00:00 2001 From: Anish Sarkar <104695310+AnishSarkar22@users.noreply.github.com> Date: Tue, 16 Jun 2026 01:39:00 +0530 Subject: [PATCH] refactor(web): route server proxies through SURFSENSE_BACKEND_INTERNAL_URL --- surfsense_web/app/api/v1/[...path]/route.ts | 6 +- surfsense_web/app/auth/[...path]/route.ts | 74 +++++++++++++++++++++ surfsense_web/app/verify-token/route.ts | 14 ++-- 3 files changed, 88 insertions(+), 6 deletions(-) create mode 100644 surfsense_web/app/auth/[...path]/route.ts diff --git a/surfsense_web/app/api/v1/[...path]/route.ts b/surfsense_web/app/api/v1/[...path]/route.ts index 418bf1a33..66ea78af5 100644 --- a/surfsense_web/app/api/v1/[...path]/route.ts +++ b/surfsense_web/app/api/v1/[...path]/route.ts @@ -14,7 +14,11 @@ const HOP_BY_HOP_HEADERS = new Set([ ]); function getBackendBaseUrl() { - const base = process.env.FASTAPI_BACKEND_INTERNAL_URL || "http://localhost:8000"; + const base = + process.env.SURFSENSE_BACKEND_INTERNAL_URL || + // TODO: Remove FASTAPI_BACKEND_INTERNAL_URL after the post-Caddy env migration window. + process.env.FASTAPI_BACKEND_INTERNAL_URL || + "http://backend:8000"; return base.endsWith("/") ? base.slice(0, -1) : base; } diff --git a/surfsense_web/app/auth/[...path]/route.ts b/surfsense_web/app/auth/[...path]/route.ts new file mode 100644 index 000000000..923f6eef3 --- /dev/null +++ b/surfsense_web/app/auth/[...path]/route.ts @@ -0,0 +1,74 @@ +import type { NextRequest } from "next/server"; + +export const dynamic = "force-dynamic"; + +const HOP_BY_HOP_HEADERS = new Set([ + "connection", + "keep-alive", + "proxy-authenticate", + "proxy-authorization", + "te", + "trailer", + "transfer-encoding", + "upgrade", +]); + +function getBackendBaseUrl() { + const base = + process.env.SURFSENSE_BACKEND_INTERNAL_URL || + // TODO: Remove FASTAPI_BACKEND_INTERNAL_URL after the post-Caddy env migration window. + process.env.FASTAPI_BACKEND_INTERNAL_URL || + "http://backend:8000"; + return base.endsWith("/") ? base.slice(0, -1) : base; +} + +function toUpstreamHeaders(headers: Headers) { + const nextHeaders = new Headers(headers); + nextHeaders.delete("host"); + nextHeaders.delete("content-length"); + return nextHeaders; +} + +function toClientHeaders(headers: Headers) { + const nextHeaders = new Headers(headers); + for (const header of HOP_BY_HOP_HEADERS) { + nextHeaders.delete(header); + } + return nextHeaders; +} + +async function proxy(request: NextRequest, context: { params: Promise<{ path?: string[] }> }) { + const params = await context.params; + const path = params.path?.join("/") || ""; + const upstreamUrl = new URL(`${getBackendBaseUrl()}/auth/${path}`); + upstreamUrl.search = request.nextUrl.search; + + const hasBody = request.method !== "GET" && request.method !== "HEAD"; + + const response = await fetch(upstreamUrl, { + method: request.method, + headers: toUpstreamHeaders(request.headers), + body: hasBody ? request.body : undefined, + // `duplex: "half"` is required by the Fetch spec when streaming a + // ReadableStream as the request body. Avoids buffering uploads in heap. + // @ts-expect-error - `duplex` is not yet in lib.dom RequestInit types. + duplex: hasBody ? "half" : undefined, + redirect: "manual", + }); + + return new Response(response.body, { + status: response.status, + statusText: response.statusText, + headers: toClientHeaders(response.headers), + }); +} + +export { + proxy as GET, + proxy as POST, + proxy as PUT, + proxy as PATCH, + proxy as DELETE, + proxy as OPTIONS, + proxy as HEAD, +}; diff --git a/surfsense_web/app/verify-token/route.ts b/surfsense_web/app/verify-token/route.ts index b7ed762de..9df460779 100644 --- a/surfsense_web/app/verify-token/route.ts +++ b/surfsense_web/app/verify-token/route.ts @@ -1,12 +1,16 @@ import { type NextRequest, NextResponse } from "next/server"; -const backendBaseUrl = (process.env.INTERNAL_FASTAPI_BACKEND_URL || "http://backend:8000").replace( - /\/+$/, - "" -); +function getBackendBaseUrl() { + const base = + process.env.SURFSENSE_BACKEND_INTERNAL_URL || + // TODO: Remove FASTAPI_BACKEND_INTERNAL_URL after the post-Caddy env migration window. + process.env.FASTAPI_BACKEND_INTERNAL_URL || + "http://backend:8000"; + return base.replace(/\/+$/, ""); +} export async function GET(request: NextRequest) { - const response = await fetch(`${backendBaseUrl}/verify-token`, { + const response = await fetch(`${getBackendBaseUrl()}/verify-token`, { method: "GET", headers: { Authorization: request.headers.get("authorization") || "",