Skip to content

Commit 7adeb8e

Browse files
committed
fix: prevent duplicate Location and x-nextjs-stale-time headers on redirect
When a page redirect is rendered, the render phase sets Location via setHeader on the response. Then the cache serving code in app-page.ts re-applies cached headers using the native appendHeader, which appends unconditionally without checking for existing values. This produces duplicate Location headers (e.g. Location: /redirect, Location: /redirect). Behind Cloudflare or similar proxies, duplicated Location headers get merged into "Location: /redirect, /redirect" which is an invalid redirect target, breaking navigation entirely. Use setHeader (replace) instead of appendHeader (add) for headers that don't support multiple values. Keep appendHeader for set-cookie, vary, www-authenticate, and proxy-authenticate which are multi-value by spec. Fixes #82117
1 parent dfbf3c4 commit 7adeb8e

File tree

1 file changed

+23
-2
lines changed

1 file changed

+23
-2
lines changed

packages/next/src/build/templates/app-page.ts

Lines changed: 23 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1608,18 +1608,39 @@ export async function handler(
16081608
delete headers[NEXT_CACHE_TAGS_HEADER]
16091609
}
16101610

1611+
// Headers that support multiple values must use appendHeader;
1612+
// all others use setHeader to avoid duplicates when the render
1613+
// phase already set the same header (e.g. Location) (#82117).
1614+
const multiValueHeaders = new Set([
1615+
'set-cookie',
1616+
'www-authenticate',
1617+
'proxy-authenticate',
1618+
'vary',
1619+
])
1620+
16111621
for (let [key, value] of Object.entries(headers)) {
16121622
if (typeof value === 'undefined') continue
16131623

1624+
const useAppend =
1625+
Array.isArray(value) || multiValueHeaders.has(key.toLowerCase())
1626+
16141627
if (Array.isArray(value)) {
16151628
for (const v of value) {
16161629
res.appendHeader(key, v)
16171630
}
16181631
} else if (typeof value === 'number') {
16191632
value = value.toString()
1620-
res.appendHeader(key, value)
1633+
if (useAppend) {
1634+
res.appendHeader(key, value)
1635+
} else {
1636+
res.setHeader(key, value)
1637+
}
16211638
} else {
1622-
res.appendHeader(key, value)
1639+
if (useAppend) {
1640+
res.appendHeader(key, value)
1641+
} else {
1642+
res.setHeader(key, value)
1643+
}
16231644
}
16241645
}
16251646
}

0 commit comments

Comments
 (0)