-
Notifications
You must be signed in to change notification settings - Fork 26.8k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Fix duplicate headers in response to static assets if overrides speci…
…fied by user (#70127) Fixes #70086 and #64864 (partially) ### What? When user wants to override for certain headers such as `content-type` or `cache-control` via `next.config` file or through middleware, nextjs sends multiple header values by combining the user's headers with its own default values for such headers. An example is demonstrated here: https://github.com/user-attachments/assets/7b38331b-9137-485d-9285-d0b0d0e1e5ac ### Why? Duplicate header values are a problem. ### How? Maintaining a list of headers which cannot have duplicate values, and then checking if the user has overridden any of those headers. If so, user overrides are respected and sent over. Demonstration of the correct behaviour after this fix: Using `next.config` file: https://github.com/user-attachments/assets/65e2aafb-dffc-47f4-bfcf-cf26a66865db Using `middleware`: https://github.com/user-attachments/assets/67636145-10eb-4504-ad78-800c1307c550 --------- Co-authored-by: JJ Kasper <jj@jjsweb.site>
- Loading branch information
Showing
12 changed files
with
109 additions
and
1 deletion.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Binary file not shown.
8 changes: 8 additions & 0 deletions
8
test/e2e/app-dir/no-duplicate-headers-middleware/app/layout.tsx
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,8 @@ | ||
import { ReactNode } from 'react' | ||
export default function Root({ children }: { children: ReactNode }) { | ||
return ( | ||
<html> | ||
<body>{children}</body> | ||
</html> | ||
) | ||
} |
3 changes: 3 additions & 0 deletions
3
test/e2e/app-dir/no-duplicate-headers-middleware/app/page.tsx
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,3 @@ | ||
export default function Page() { | ||
return <p>hello world</p> | ||
} |
13 changes: 13 additions & 0 deletions
13
test/e2e/app-dir/no-duplicate-headers-middleware/middleware.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,13 @@ | ||
import { NextResponse } from 'next/server' | ||
import type { NextRequest } from 'next/server' | ||
|
||
export function middleware(request: NextRequest) { | ||
if (request.nextUrl.pathname === '/favicon.ico') { | ||
return NextResponse.next({ | ||
headers: { | ||
'Cache-Control': 'max-age=1234', | ||
'Content-Type': 'image/vnd.microsoft.icon', | ||
}, | ||
}) | ||
} | ||
} |
6 changes: 6 additions & 0 deletions
6
test/e2e/app-dir/no-duplicate-headers-middleware/next.config.js
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,6 @@ | ||
/** | ||
* @type {import('next').NextConfig} | ||
*/ | ||
const nextConfig = {} | ||
|
||
module.exports = nextConfig |
14 changes: 14 additions & 0 deletions
14
test/e2e/app-dir/no-duplicate-headers-middleware/no-duplicate-headers-middleware.test.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,14 @@ | ||
import { nextTestSetup } from 'e2e-utils' | ||
|
||
describe('no-duplicate-headers-next-config', () => { | ||
const { next } = nextTestSetup({ | ||
files: __dirname, | ||
}) | ||
|
||
it('should prioritise headers in middleware for static assets', async () => { | ||
const res = await next.fetch('favicon.ico') | ||
expect(res.status).toBe(200) | ||
expect(res.headers.get('cache-control')).toBe('max-age=1234') | ||
expect(res.headers.get('content-type')).toBe('image/vnd.microsoft.icon') | ||
}) | ||
}) |
Binary file not shown.
8 changes: 8 additions & 0 deletions
8
test/e2e/app-dir/no-duplicate-headers-next-config/app/layout.tsx
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,8 @@ | ||
import { ReactNode } from 'react' | ||
export default function Root({ children }: { children: ReactNode }) { | ||
return ( | ||
<html> | ||
<body>{children}</body> | ||
</html> | ||
) | ||
} |
3 changes: 3 additions & 0 deletions
3
test/e2e/app-dir/no-duplicate-headers-next-config/app/page.tsx
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,3 @@ | ||
export default function Page() { | ||
return <p>hello world</p> | ||
} |
24 changes: 24 additions & 0 deletions
24
test/e2e/app-dir/no-duplicate-headers-next-config/next.config.js
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,24 @@ | ||
/** | ||
* @type {import('next').NextConfig} | ||
*/ | ||
const nextConfig = { | ||
async headers() { | ||
return [ | ||
{ | ||
source: '/favicon.ico', | ||
headers: [ | ||
{ | ||
key: 'cache-control', | ||
value: 'max-age=1234', | ||
}, | ||
{ | ||
key: 'content-type', | ||
value: 'image/vnd.microsoft.icon', | ||
}, | ||
], | ||
}, | ||
] | ||
}, | ||
} | ||
|
||
module.exports = nextConfig |
14 changes: 14 additions & 0 deletions
14
test/e2e/app-dir/no-duplicate-headers-next-config/no-duplicate-headers-next-config.test.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,14 @@ | ||
import { nextTestSetup } from 'e2e-utils' | ||
|
||
describe('no-duplicate-headers-next-config', () => { | ||
const { next } = nextTestSetup({ | ||
files: __dirname, | ||
}) | ||
|
||
it('should prioritise headers in next config for static assets', async () => { | ||
const res = await next.fetch('favicon.ico') | ||
expect(res.status).toBe(200) | ||
expect(res.headers.get('cache-control')).toBe('max-age=1234') | ||
expect(res.headers.get('content-type')).toBe('image/vnd.microsoft.icon') | ||
}) | ||
}) |