diff --git a/.changeset/clever-readers-turn.md b/.changeset/clever-readers-turn.md new file mode 100644 index 000000000000..c48d4bbb3d30 --- /dev/null +++ b/.changeset/clever-readers-turn.md @@ -0,0 +1,5 @@ +--- +'@sveltejs/kit': patch +--- + +Preserve explicit ETag header diff --git a/packages/kit/src/runtime/server/index.js b/packages/kit/src/runtime/server/index.js index 8b152b6f496c..9692866bbfa7 100644 --- a/packages/kit/src/runtime/server/index.js +++ b/packages/kit/src/runtime/server/index.js @@ -122,8 +122,9 @@ export async function respond(incoming, options, state = {}) { : await render_page(request, route, match, options, state, ssr); if (response) { - // inject ETags for 200 responses - if (response.status === 200) { + // inject ETags for 200 responses, if the endpoint + // doesn't have its own ETag handling + if (response.status === 200 && !response.headers.etag) { const cache_control = get_single_valued_header(response.headers, 'cache-control'); if (!cache_control || !/(no-store|immutable)/.test(cache_control)) { let if_none_match_value = request.headers['if-none-match']; diff --git a/packages/kit/test/apps/basics/src/routes/etag/custom.js b/packages/kit/test/apps/basics/src/routes/etag/custom.js new file mode 100644 index 000000000000..71136e3a2f13 --- /dev/null +++ b/packages/kit/test/apps/basics/src/routes/etag/custom.js @@ -0,0 +1,10 @@ +/** @type {import('@sveltejs/kit').RequestHandler} */ +export function get({ headers }) { + if (headers['if-none-match'] === '@1234@') return { status: 304 }; + return { + body: `${Math.random()}`, + headers: { + etag: '@1234@' + } + }; +} diff --git a/packages/kit/test/apps/basics/test/test.js b/packages/kit/test/apps/basics/test/test.js index d6a936c22bff..469ebe3d9eeb 100644 --- a/packages/kit/test/apps/basics/test/test.js +++ b/packages/kit/test/apps/basics/test/test.js @@ -732,6 +732,20 @@ test.describe.parallel('ETags', () => { expect(r2.status()).toBe(304); }); + + test('custom etag', async ({ request }) => { + const r1 = await request.get('/etag/custom'); + const etag = r1.headers()['etag']; + expect(etag).toBe('@1234@'); + + const r2 = await request.get('/etag/custom', { + headers: { + 'if-none-match': '@1234@' + } + }); + + expect(r2.status()).toBe(304); + }); }); test.describe.parallel('Headers', () => {