diff --git a/src/runtime/internal/static.ts b/src/runtime/internal/static.ts index 81db44b068..95c0599230 100644 --- a/src/runtime/internal/static.ts +++ b/src/runtime/internal/static.ts @@ -6,6 +6,7 @@ import { getResponseHeader, removeResponseHeader, setResponseHeader, + appendResponseHeader, setResponseStatus, } from "h3"; import type { PublicAsset } from "nitropack/types"; @@ -49,7 +50,7 @@ export default eventHandler((event) => { "", ]; if (encodings.length > 1) { - setResponseHeader(event, "Vary", "Accept-Encoding"); + appendResponseHeader(event, "Vary", "Accept-Encoding"); } for (const encoding of encodings) { diff --git a/test/fixture/plugins/vary.ts b/test/fixture/plugins/vary.ts new file mode 100644 index 0000000000..d1dcd40d17 --- /dev/null +++ b/test/fixture/plugins/vary.ts @@ -0,0 +1,10 @@ +export default defineNitroPlugin((app) => { + app.hooks.hook("request", (event) => { + if (event.path.endsWith(".css")) { + setResponseHeader(event, "Vary", "Origin"); + } + if (event.path.endsWith(".js")) { + setResponseHeader(event, "Vary", ["Origin"]); + } + }); +}); diff --git a/test/fixture/public/foo.css b/test/fixture/public/foo.css new file mode 100644 index 0000000000..e69de29bb2 diff --git a/test/fixture/public/foo.js b/test/fixture/public/foo.js new file mode 100644 index 0000000000..a9917c6ec3 --- /dev/null +++ b/test/fixture/public/foo.js @@ -0,0 +1 @@ +const hello = "world"; diff --git a/test/presets/cloudflare-pages.test.ts b/test/presets/cloudflare-pages.test.ts index f6bbf25f9b..4b5a3d5af6 100644 --- a/test/presets/cloudflare-pages.test.ts +++ b/test/presets/cloudflare-pages.test.ts @@ -48,6 +48,8 @@ describe.skipIf(isWindows)("nitro:preset:cloudflare-pages", async () => { "/_swagger", "/_unignored.txt", "/favicon.ico", + "/foo.css", + "/foo.js", "/json-string", "/prerender", "/prerender-custom", diff --git a/test/tests.ts b/test/tests.ts index a908b4335f..5dbba0961f 100644 --- a/test/tests.ts +++ b/test/tests.ts @@ -311,6 +311,43 @@ export function testNitro( expect(data).toMatch("

Hello JSX!

"); }); + it.runIf(ctx.nitro?.options.serveStatic)( + "handles custom Vary header", + async () => { + let headers = ( + await callHandler({ + url: "/foo.css", + headers: { "Accept-Encoding": "gzip" }, + }) + ).headers; + if (headers["vary"]) + expect( + headers["vary"].includes("Origin") && + headers["vary"].includes("Accept-Encoding") + ).toBeTruthy(); + + headers = ( + await callHandler({ + url: "/foo.css", + headers: { "Accept-Encoding": "" }, + }) + ).headers; + if (headers["vary"]) expect(headers["vary"]).toBe("Origin"); + + headers = ( + await callHandler({ + url: "/foo.js", + headers: { "Accept-Encoding": "gzip" }, + }) + ).headers; + if (headers["vary"]) + expect( + headers["vary"].includes("Origin") && + headers["vary"].includes("Accept-Encoding") + ).toBeTruthy(); + } + ); + it("handles route rules - headers", async () => { const { headers } = await callHandler({ url: "/rules/headers" }); expect(headers["cache-control"]).toBe("s-maxage=60");