import { NextRequest } from "next/server" import { env } from "@/env/server" /** * Use this function when you want to create URLs that are public facing, for * example for redirects or redirectTo query parameters. * Dedicated environments are behind Akamai (test, stage, production). They have * env.PUBLIC_URL set. * All other environment like deploy previews and branch deployments are not * behind Akamai and therefore do not have env.PUBLIC_URL set. * We need this approach because Netlify uses x-forwarded-host internally and * strips it from ever reaching our code. * TODO: Replace this approach with custom header in Akamai that mirrors the * value in x-forwarded-host which would not get stripped by Netlify. * @param request The incoming request. * @returns NextURL The public facing URL instance for the given request. */ export function getPublicNextURL(request: NextRequest) { if (env.PUBLIC_URL) { const publicNextURL = request.nextUrl.clone() // Akamai in front of Netlify for dedicated environments // require us to rewrite the incoming host and hostname // to match the public URL used to visit Akamai. const url = new URL(env.PUBLIC_URL) publicNextURL.host = url.host publicNextURL.hostname = url.hostname return publicNextURL } return request.nextUrl } /** * Use this function when you want the public facing URL for the given request. * Read about the motivation in getPublicNextURL above. * @see getPublicNextURL * @param request The incoming request. * @returns string The public facing origin for the given request. */ export function getPublicURL(request: NextRequest) { if (env.PUBLIC_URL) { return env.PUBLIC_URL } return request.nextUrl.origin } /** * Use this function when you want to create URLs that are internal (behind Akamai), * for example for rewrites. Mainly used for middleware wrapped in auth(). * The auth() function overrides the origin of the incoming request. It sets it * to the origin of AUTH_URL/NEXTAUTH_URL. This means we cannot use the augmented * request from auth() for rewrites, as those will point to auth url origin * (in front of Akamai) and not the origin of the incoming request (behind Akamai). * This results in rewrites going over the internet instead of going through the * internal routing at Netlify. * For dedicated environments (test, stage and production) we are behind Akamai. * For those we have set a value for AUTH_URL/NEXTAUTH_URL, they point to the * PUBLIC_URL. For rewrites we need the internal origin inside Netlify. * In middleware.ts we copy the incoming origin to a header 'x-sh-origin'. We try * and use that first, if not present we assume the internal origin is the value * of the host header, as that is what Netlify used for routing to this deployment. * @param request The incoming request. * @returns NextURL The internal request, in Netlify behind Akamai. */ export function getInternalNextURL(request: NextRequest) { const { href, origin } = request.nextUrl const originHeader = request.headers.get("x-sh-origin") if (originHeader) { console.log(`[internalNextUrl] using x-sh-origin header`, { origin, originHeader, newOrigin: href.replace(origin, originHeader), }) return new NextRequest(href.replace(origin, originHeader), request).nextUrl } const hostHeader = request.headers.get("host") if (hostHeader) { const inputHostOrigin = `${request.nextUrl.protocol}//${hostHeader}` console.log(`[internalNextUrl] using host header`, { origin, hostHeader, hostOrigin: inputHostOrigin, newOrigin: href.replace(origin, inputHostOrigin), }) const { origin: hostOrigin } = new URL(inputHostOrigin) return new NextRequest(href.replace(origin, hostOrigin), request).nextUrl } console.log(`[internalNextUrl] falling back to incoming request`) return request.nextUrl }