Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Strip internal routing headers #55114

Merged
merged 2 commits into from
Sep 7, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
27 changes: 27 additions & 0 deletions packages/next/src/server/base-server.ts
Original file line number Diff line number Diff line change
Expand Up @@ -124,6 +124,7 @@ import {
} from './web/spec-extension/adapters/next-request'
import { matchNextDataPathname } from './lib/match-next-data-pathname'
import getRouteFromAssetPath from '../shared/lib/router/utils/get-route-from-asset-path'
import { stripInternalHeaders } from './internal-utils'

export type FindComponentsResult = {
components: LoadComponentsReturnType
Expand Down Expand Up @@ -1538,6 +1539,28 @@ export default abstract class Server<ServerOptions extends Options = Options> {
)
}

protected stripInternalHeaders(req: BaseNextRequest): void {
// Skip stripping internal headers in test mode while the header stripping
// has been explicitly disabled. This allows tests to verify internal
// routing behavior.
if (
process.env.__NEXT_TEST_MODE &&
process.env.__NEXT_NO_STRIP_INTERNAL_HEADERS === '1'
) {
return
}

// Strip the internal headers from both the request and the original
// request.
stripInternalHeaders(req.headers)
if (
'originalRequest' in req &&
'headers' in (req as NodeNextRequest).originalRequest
) {
stripInternalHeaders((req as NodeNextRequest).originalRequest.headers)
}
}

private async renderToResponseWithComponentsImpl(
{ req, res, pathname, renderOpts: opts }: RequestContext,
{ components, query }: FindComponentsResult
Expand All @@ -1546,6 +1569,10 @@ export default abstract class Server<ServerOptions extends Options = Options> {
// For edge runtime 404 page, /_not-found needs to be treated as 404 page
(process.env.NEXT_RUNTIME === 'edge' && pathname === '/_not-found') ||
pathname === '/404'

// Strip the internal headers.
this.stripInternalHeaders(req)

const is500Page = pathname === '/500'
const isAppPath = components.isAppPath
const hasServerProps = !!components.getServerSideProps
Expand Down
28 changes: 27 additions & 1 deletion packages/next/src/server/internal-utils.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
import { NEXT_RSC_UNION_QUERY } from '../client/components/app-router-headers'
import type { IncomingHttpHeaders } from 'http'
import type { NextParsedUrlQuery } from './request-meta'

import { NEXT_RSC_UNION_QUERY } from '../client/components/app-router-headers'

const INTERNAL_QUERY_NAMES = [
'__nextFallback',
'__nextLocale',
Expand Down Expand Up @@ -36,3 +38,27 @@ export function stripInternalSearchParams<T extends string | URL>(

return (isStringUrl ? instance.toString() : instance) as T
}

/**
* Headers that are set by the Next.js server and should be stripped from the
* request headers going to the user's application.
*/
const INTERNAL_HEADERS = [
'x-invoke-path',
'x-invoke-status',
'x-invoke-error',
'x-invoke-query',
'x-invoke-output',
'x-middleware-invoke',
] as const

/**
* Strip internal headers from the request headers.
*
* @param headers the headers to strip of internal headers
*/
export function stripInternalHeaders(headers: IncomingHttpHeaders) {
for (const key of INTERNAL_HEADERS) {
delete headers[key]
}
}
3 changes: 3 additions & 0 deletions packages/next/src/server/next-server.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1585,6 +1585,9 @@ export default class NextNodeServer extends BaseServer {
ReturnType<typeof NextNodeServer.prototype.runMiddleware>
>

// Strip the internal headers.
this.stripInternalHeaders(req)

try {
await this.ensureMiddleware()

Expand Down
4 changes: 4 additions & 0 deletions test/e2e/i18n-data-route/i18n-data-route.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,10 @@ createNextDescribe(
'i18n-data-route',
{
files: __dirname,
env: {
// Disable internal header stripping so we can test the invoke output.
__NEXT_NO_STRIP_INTERNAL_HEADERS: '1',
},
},
({ next }) => {
describe('with locale prefix', () => {
Expand Down