Skip to content

Commit 46f89b0

Browse files
authored
[ppr] Request normalization fixes (#65717)
This resolves an issue where a prefetch react server components (RSC) request incorrectly causes cache poisoning issues during revalidation for applications configured with partial prerendering (PPR). It removes the test which used the header directly, and instead defers to the `handleRSCRequest` method which includes specific environment implementations. This also fixes a bug where the prefetch RSC request for the root page was not normalized.
1 parent add70da commit 46f89b0

File tree

4 files changed

+65
-19
lines changed

4 files changed

+65
-19
lines changed

packages/next/src/server/base-server.ts

Lines changed: 28 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -620,7 +620,14 @@ export default abstract class Server<
620620
// revalidation requests and we want the cache to instead depend on the
621621
// request path for flight information.
622622
stripFlightHeaders(req.headers)
623+
623624
return false
625+
} else if (req.headers[RSC_HEADER.toLowerCase()] === '1') {
626+
addRequestMeta(req, 'isRSCRequest', true)
627+
628+
if (req.headers[NEXT_ROUTER_PREFETCH_HEADER.toLowerCase()] === '1') {
629+
addRequestMeta(req, 'isPrefetchRSCRequest', true)
630+
}
624631
} else {
625632
// Otherwise just return without doing anything.
626633
return false
@@ -808,27 +815,30 @@ export default abstract class Server<
808815
): Promise<void> {
809816
await this.prepare()
810817
const method = req.method.toUpperCase()
811-
const rsc = isRSCRequestCheck(req) ? 'RSC ' : ''
812818

813819
const tracer = getTracer()
814820
return tracer.withPropagatedContext(req.headers, () => {
815821
return tracer.trace(
816822
BaseServerSpan.handleRequest,
817823
{
818-
spanName: `${rsc}${method} ${req.url}`,
824+
spanName: `${method} ${req.url}`,
819825
kind: SpanKind.SERVER,
820826
attributes: {
821827
'http.method': method,
822828
'http.target': req.url,
823-
'next.rsc': Boolean(rsc),
824829
},
825830
},
826831
async (span) =>
827832
this.handleRequestImpl(req, res, parsedUrl).finally(() => {
828833
if (!span) return
834+
835+
const isRSCRequest = isRSCRequestCheck(req) ?? false
836+
829837
span.setAttributes({
830838
'http.status_code': res.statusCode,
839+
'next.rsc': isRSCRequest,
831840
})
841+
832842
const rootSpanAttributes = tracer.getRootSpanAttributes()
833843
// We were unable to get attributes, probably OTEL is not enabled
834844
if (!rootSpanAttributes) return
@@ -847,13 +857,22 @@ export default abstract class Server<
847857

848858
const route = rootSpanAttributes.get('next.route')
849859
if (route) {
850-
const newName = `${rsc}${method} ${route}`
860+
const name = isRSCRequest
861+
? `RSC ${method} ${route}`
862+
: `${method} ${route}`
863+
851864
span.setAttributes({
852865
'next.route': route,
853866
'http.route': route,
854-
'next.span_name': newName,
867+
'next.span_name': name,
855868
})
856-
span.updateName(newName)
869+
span.updateName(name)
870+
} else {
871+
span.updateName(
872+
isRSCRequest
873+
? `RSC ${method} ${req.url}`
874+
: `${method} ${req.url}`
875+
)
857876
}
858877
})
859878
)
@@ -928,11 +947,8 @@ export default abstract class Server<
928947
// it captures the initial URL.
929948
this.attachRequestMeta(req, parsedUrl)
930949

931-
let finished: boolean = false
932-
if (this.minimalMode && this.enabledDirectories.app) {
933-
finished = await this.handleRSCRequest(req, res, parsedUrl)
934-
if (finished) return
935-
}
950+
let finished = await this.handleRSCRequest(req, res, parsedUrl)
951+
if (finished) return
936952

937953
const domainLocale = this.i18nProvider?.detectDomainLocale(
938954
getHostname(parsedUrl, req.headers)
@@ -3588,8 +3604,5 @@ export default abstract class Server<
35883604
}
35893605

35903606
export function isRSCRequestCheck(req: BaseNextRequest): boolean {
3591-
return (
3592-
req.headers[RSC_HEADER.toLowerCase()] === '1' ||
3593-
Boolean(getRequestMeta(req, 'isRSCRequest'))
3594-
)
3607+
return getRequestMeta(req, 'isRSCRequest') === true
35953608
}
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
import { PrefetchRSCPathnameNormalizer } from './prefetch-rsc'
2+
3+
describe('PrefetchRSCPathnameNormalizer', () => {
4+
const normalizer = new PrefetchRSCPathnameNormalizer()
5+
6+
it('should match the prefetch rsc pathname', () => {
7+
expect(normalizer.match('/blog/post.prefetch.rsc')).toBe(true)
8+
})
9+
10+
it('should not match the prefetch rsc pathname with a different suffix', () => {
11+
expect(normalizer.match('/blog/post.prefetch.rsc2')).toBe(false)
12+
})
13+
14+
it('should normalize the prefetch rsc pathname', () => {
15+
expect(normalizer.normalize('/blog/post.prefetch.rsc')).toBe('/blog/post')
16+
})
17+
18+
it('should normalize the prefetch rsc index pathname', () => {
19+
expect(normalizer.normalize('/__index.prefetch.rsc')).toBe('/')
20+
})
21+
})

packages/next/src/server/future/normalizers/request/prefetch-rsc.ts

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,4 +10,20 @@ export class PrefetchRSCPathnameNormalizer
1010
constructor() {
1111
super(RSC_PREFETCH_SUFFIX)
1212
}
13+
14+
public match(pathname: string): boolean {
15+
if (pathname === '/__index' + RSC_PREFETCH_SUFFIX) {
16+
return true
17+
}
18+
19+
return super.match(pathname)
20+
}
21+
22+
public normalize(pathname: string, matched?: boolean): string {
23+
if (pathname === '/__index' + RSC_PREFETCH_SUFFIX) {
24+
return '/'
25+
}
26+
27+
return super.normalize(pathname, matched)
28+
}
1329
}

packages/next/src/server/next-server.ts

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1810,10 +1810,6 @@ export default class NextNodeServer extends BaseServer<
18101810
? `https://${req.headers.host || 'localhost'}${req.url}`
18111811
: req.url
18121812

1813-
const isRSC = isRSCRequestCheck(req)
1814-
if (isRSC) {
1815-
addRequestMeta(req, 'isRSCRequest', true)
1816-
}
18171813
addRequestMeta(req, 'initURL', initUrl)
18181814
addRequestMeta(req, 'initQuery', { ...parsedUrl.query })
18191815
addRequestMeta(req, 'initProtocol', protocol)

0 commit comments

Comments
 (0)