diff --git a/packages/next/src/server/lib/router-server.ts b/packages/next/src/server/lib/router-server.ts index 20aab194b29523..d5b27c17fe143b 100644 --- a/packages/next/src/server/lib/router-server.ts +++ b/packages/next/src/server/lib/router-server.ts @@ -149,6 +149,12 @@ export async function initialize(opts: { renderServer.instance = require('./render-server') as typeof import('./render-server') + const randomBytes = new Uint8Array(8) + crypto.getRandomValues(randomBytes) + const middlewareSubrequestId = Buffer.from(randomBytes).toString('hex') + ;(globalThis as any)[Symbol.for('@next/middleware-subrequest-id')] = + middlewareSubrequestId + const requestHandlerImpl: WorkerRequestHandler = async (req, res) => { // internal headers should not be honored by the request handler if (!process.env.NEXT_PRIVATE_TEST_HEADERS) { diff --git a/packages/next/src/server/lib/server-ipc/utils.ts b/packages/next/src/server/lib/server-ipc/utils.ts index 09dee95773625d..0b82fdb3f8df9e 100644 --- a/packages/next/src/server/lib/server-ipc/utils.ts +++ b/packages/next/src/server/lib/server-ipc/utils.ts @@ -57,5 +57,16 @@ export const filterInternalHeaders = ( if (INTERNAL_HEADERS.includes(header)) { delete headers[header] } + + // If this request didn't origin from this session we filter + // out the "x-middleware-subrequest" header so we don't skip + // middleware incorrectly + if ( + header === 'x-middleware-subrequest' && + headers['x-middleware-subrequest-id'] !== + (globalThis as any)[Symbol.for('@next/middleware-subrequest-id')] + ) { + delete headers['x-middleware-subrequest'] + } } } diff --git a/packages/next/src/server/web/sandbox/context.ts b/packages/next/src/server/web/sandbox/context.ts index 899758cb46f2a8..b4588817fcdda8 100644 --- a/packages/next/src/server/web/sandbox/context.ts +++ b/packages/next/src/server/web/sandbox/context.ts @@ -365,6 +365,10 @@ Learn More: https://nextjs.org/docs/messages/edge-dynamic-code-evaluation`), store.headers.get('x-middleware-subrequest') ?? '' ) } + init.headers.set( + 'x-middleware-subrequest-id', + (globalThis as any)[Symbol.for('@next/middleware-subrequest-id')] + ) const prevs = init.headers.get(`x-middleware-subrequest`)?.split(':') || [] diff --git a/test/e2e/middleware-general/test/index.test.ts b/test/e2e/middleware-general/test/index.test.ts index 70e5c8a2590f9a..5e9af61a32b537 100644 --- a/test/e2e/middleware-general/test/index.test.ts +++ b/test/e2e/middleware-general/test/index.test.ts @@ -102,6 +102,19 @@ describe('Middleware Runtime', () => { } function runTests({ i18n }: { i18n?: boolean }) { + it('should filter request header properly', async () => { + const res = await next.fetch('/redirect-to-somewhere', { + headers: { + 'x-middleware-subrequest': + 'middleware:middleware:middleware:middleware:middleware', + }, + redirect: 'manual', + }) + + expect(res.status).toBe(307) + expect(res.headers.get('location')).toContain('/somewhere') + }) + it('should handle 404 on fallback: false route correctly', async () => { const res = await next.fetch('/ssg-fallback-false/first') expect(res.status).toBe(200)