diff --git a/.changeset/giant-vans-shop.md b/.changeset/giant-vans-shop.md new file mode 100644 index 000000000..e1343bf3c --- /dev/null +++ b/.changeset/giant-vans-shop.md @@ -0,0 +1,5 @@ +--- +"@opennextjs/aws": patch +--- + +Hides the x-opennext header from server requests when poweredByHeader is false in next config diff --git a/examples/pages-router/next.config.js b/examples/pages-router/next.config.js index 98e1bb953..5e3af8c9d 100644 --- a/examples/pages-router/next.config.js +++ b/examples/pages-router/next.config.js @@ -53,6 +53,7 @@ const nextConfig = { }, ], trailingSlash: true, + poweredByHeader: true, }; module.exports = nextConfig; diff --git a/packages/open-next/src/core/routing/util.ts b/packages/open-next/src/core/routing/util.ts index 498a974a5..08084f6d8 100644 --- a/packages/open-next/src/core/routing/util.ts +++ b/packages/open-next/src/core/routing/util.ts @@ -2,7 +2,7 @@ import crypto from "node:crypto"; import { OutgoingHttpHeaders } from "node:http"; import { Readable } from "node:stream"; -import { BuildId, HtmlPages } from "config/index.js"; +import { BuildId, HtmlPages, NextConfig } from "config/index.js"; import type { IncomingMessage, StreamCreator } from "http/index.js"; import { OpenNextNodeResponse } from "http/openNextResponse.js"; import { parseHeaders } from "http/util.js"; @@ -322,7 +322,9 @@ export function fixSWRCacheHeader(headers: OutgoingHttpHeaders) { * @__PURE__ */ export function addOpenNextHeader(headers: OutgoingHttpHeaders) { - headers["X-OpenNext"] = "1"; + if (NextConfig.poweredByHeader) { + headers["X-OpenNext"] = "1"; + } if (globalThis.openNextDebug) { headers["X-OpenNext-Version"] = globalThis.openNextVersion; headers["X-OpenNext-RequestId"] = globalThis.__als.getStore()?.requestId; diff --git a/packages/open-next/src/types/next-types.ts b/packages/open-next/src/types/next-types.ts index 8a5aa5c7a..b9640528d 100644 --- a/packages/open-next/src/types/next-types.ts +++ b/packages/open-next/src/types/next-types.ts @@ -75,6 +75,7 @@ export interface NextConfig { appDir?: boolean; }; images: ImageConfig; + poweredByHeader?: boolean; } export interface RouteDefinition { diff --git a/packages/tests-e2e/tests/appRouter/headers.test.ts b/packages/tests-e2e/tests/appRouter/headers.test.ts index 96f6512d4..192918a58 100644 --- a/packages/tests-e2e/tests/appRouter/headers.test.ts +++ b/packages/tests-e2e/tests/appRouter/headers.test.ts @@ -20,4 +20,8 @@ test("Headers", async ({ page }) => { // Request header should be available in RSC let el = page.getByText(`request-header`); await expect(el).toBeVisible(); + + // Both these headers should not be present cause poweredByHeader is false in appRouter + expect(headers["x-powered-by"]).toBeFalsy(); + expect(headers["x-opennext"]).toBeFalsy(); }); diff --git a/packages/tests-e2e/tests/pagesRouter/header.test.ts b/packages/tests-e2e/tests/pagesRouter/header.test.ts new file mode 100644 index 000000000..e528bc194 --- /dev/null +++ b/packages/tests-e2e/tests/pagesRouter/header.test.ts @@ -0,0 +1,14 @@ +import { expect, test } from "@playwright/test"; + +test("should test if poweredByHeader adds the correct headers ", async ({ + page, +}) => { + const result = await page.goto("/"); + expect(result).toBeDefined(); + expect(result?.status()).toBe(200); + const headers = result?.headers(); + + // Both these headers should be present cause poweredByHeader is true in pagesRouter + expect(headers?.["x-powered-by"]).toBe("Next.js"); + expect(headers?.["x-opennext"]).toBe("1"); +});