From 51397b9c41d5a3e8d107360169a89e82cd076afa Mon Sep 17 00:00:00 2001 From: theandrew168 Date: Sat, 17 Jan 2026 14:58:29 -0600 Subject: [PATCH 1/4] Add failing tests to isolate the issue --- tests/public/not-compressed.txt | 1 + tests/sirv.mjs | 30 ++++++++++++++++++++++++++++++ 2 files changed, 31 insertions(+) create mode 100644 tests/public/not-compressed.txt diff --git a/tests/public/not-compressed.txt b/tests/public/not-compressed.txt new file mode 100644 index 0000000..24a2688 --- /dev/null +++ b/tests/public/not-compressed.txt @@ -0,0 +1 @@ +not-compressed.txt \ No newline at end of file diff --git a/tests/sirv.mjs b/tests/sirv.mjs index b18db63..ca200c5 100644 --- a/tests/sirv.mjs +++ b/tests/sirv.mjs @@ -820,6 +820,21 @@ brotli('should be preferred when "Accept-Encoding" allows both', async () => { } }); +brotli('should not set "Vary: Accept-Encoding" when a compressed version of the requested file does not exist', async () => { + let server = utils.http({ brotli: true }); + let headers = { 'Accept-Encoding': 'br,gzip' }; + + try { + let res = await server.send('GET', '/not-compressed.txt', { headers }); + assert.is(res.headers['content-type'], 'text/plain'); + assert.is(res.headers['vary'], undefined); + assert.is(res.data, 'not-compressed.txt'); + assert.is(res.statusCode, 200); + } finally { + server.close(); + } +}); + brotli.run(); // --- @@ -885,6 +900,21 @@ gzip('should defer to brotli when "Accept-Encoding" allows both', async () => { } }); +gzip('should not set "Vary: Accept-Encoding" when a compressed version of the requested file does not exist', async () => { + let server = utils.http({ gzip: true }); + let headers = { 'Accept-Encoding': 'br,gzip' }; + + try { + let res = await server.send('GET', '/not-compressed.txt', { headers }); + assert.is(res.headers['content-type'], 'text/plain'); + assert.is(res.headers['vary'], undefined); + assert.is(res.data, 'not-compressed.txt'); + assert.is(res.statusCode, 200); + } finally { + server.close(); + } +}); + gzip.run(); // --- From 6ec669004a1cce6b174b72088e13ac740b2b3468 Mon Sep 17 00:00:00 2001 From: theandrew168 Date: Sat, 17 Jan 2026 15:31:10 -0600 Subject: [PATCH 2/4] Update the logic used to determine when to add the header --- packages/sirv/index.mjs | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/packages/sirv/index.mjs b/packages/sirv/index.mjs index 2f866d5..8b3301d 100644 --- a/packages/sirv/index.mjs +++ b/packages/sirv/index.mjs @@ -187,7 +187,13 @@ export default function (dir, opts={}) { return res.end(); } - if (gzips || brots) { + // When a users "requests" a file, sirv may "choose" a different (compressed) version based + // on the current options (gzip, brotli), request headers ("Accept-Encoding"), and available files. + // We should only set "Vary: Accept-Encoding" if a compressed version of the requested file exists + // and was chosen instead of the requested file. + const isChosenFileCompressed = !!data.headers['Content-Encoding']; + const doesChosenFileMatchRequestedFile = data.abs.endsWith(pathname); + if (isChosenFileCompressed && !doesChosenFileMatchRequestedFile) { res.setHeader('Vary', 'Accept-Encoding'); } From c3a6cd3b4dbd68c40dd17f5870ff8e50eeb65bb9 Mon Sep 17 00:00:00 2001 From: theandrew168 Date: Sat, 17 Jan 2026 15:43:03 -0600 Subject: [PATCH 3/4] Add tests for directly requesting a compressed file --- tests/public/not-compressed.txt | 2 +- tests/sirv.mjs | 34 +++++++++++++++++++++++++++++++-- 2 files changed, 33 insertions(+), 3 deletions(-) diff --git a/tests/public/not-compressed.txt b/tests/public/not-compressed.txt index 24a2688..50e2237 100644 --- a/tests/public/not-compressed.txt +++ b/tests/public/not-compressed.txt @@ -1 +1 @@ -not-compressed.txt \ No newline at end of file +not-compressed.txt diff --git a/tests/sirv.mjs b/tests/sirv.mjs index ca200c5..62f60a8 100644 --- a/tests/sirv.mjs +++ b/tests/sirv.mjs @@ -828,7 +828,22 @@ brotli('should not set "Vary: Accept-Encoding" when a compressed version of the let res = await server.send('GET', '/not-compressed.txt', { headers }); assert.is(res.headers['content-type'], 'text/plain'); assert.is(res.headers['vary'], undefined); - assert.is(res.data, 'not-compressed.txt'); + assert.is(res.data, 'not-compressed.txt\n'); + assert.is(res.statusCode, 200); + } finally { + server.close(); + } +}); + +brotli('should not set "Vary: Accept-Encoding" when a compressed file is requested directly', async () => { + let server = utils.http({ brotli: true }); + let headers = { 'Accept-Encoding': 'br,gzip' }; + + try { + let res = await server.send('GET', '/index.html.br', { headers }); + assert.is(res.headers['content-type'], 'text/html;charset=utf-8'); + assert.is(res.headers['vary'], undefined); + assert.is(res.data, 'brotli html\n'); assert.is(res.statusCode, 200); } finally { server.close(); @@ -908,7 +923,22 @@ gzip('should not set "Vary: Accept-Encoding" when a compressed version of the re let res = await server.send('GET', '/not-compressed.txt', { headers }); assert.is(res.headers['content-type'], 'text/plain'); assert.is(res.headers['vary'], undefined); - assert.is(res.data, 'not-compressed.txt'); + assert.is(res.data, 'not-compressed.txt\n'); + assert.is(res.statusCode, 200); + } finally { + server.close(); + } +}); + +gzip('should not set "Vary: Accept-Encoding" when a compressed file is requested directly', async () => { + let server = utils.http({ gzip: true }); + let headers = { 'Accept-Encoding': 'br,gzip' }; + + try { + let res = await server.send('GET', '/index.html.gz', { headers }); + assert.is(res.headers['content-type'], 'text/html;charset=utf-8'); + assert.is(res.headers['vary'], undefined); + assert.is(res.data, 'gzip html\n'); assert.is(res.statusCode, 200); } finally { server.close(); From 9c6164e3fba7258a37eb75457259d25b83fd3c02 Mon Sep 17 00:00:00 2001 From: theandrew168 Date: Sat, 17 Jan 2026 15:46:33 -0600 Subject: [PATCH 4/4] Add tests for when "Vary" _should_ be set --- tests/public/no-compressed-version.txt | 1 + tests/public/not-compressed.txt | 1 - tests/sirv.mjs | 50 ++++++++++++++++++++------ 3 files changed, 41 insertions(+), 11 deletions(-) create mode 100644 tests/public/no-compressed-version.txt delete mode 100644 tests/public/not-compressed.txt diff --git a/tests/public/no-compressed-version.txt b/tests/public/no-compressed-version.txt new file mode 100644 index 0000000..aa26038 --- /dev/null +++ b/tests/public/no-compressed-version.txt @@ -0,0 +1 @@ +no-compressed-version.txt diff --git a/tests/public/not-compressed.txt b/tests/public/not-compressed.txt deleted file mode 100644 index 50e2237..0000000 --- a/tests/public/not-compressed.txt +++ /dev/null @@ -1 +0,0 @@ -not-compressed.txt diff --git a/tests/sirv.mjs b/tests/sirv.mjs index 62f60a8..4ffa072 100644 --- a/tests/sirv.mjs +++ b/tests/sirv.mjs @@ -820,15 +820,15 @@ brotli('should be preferred when "Accept-Encoding" allows both', async () => { } }); -brotli('should not set "Vary: Accept-Encoding" when a compressed version of the requested file does not exist', async () => { +brotli('should set "Vary: Accept-Encoding" when a compressed version of the requested file exists', async () => { let server = utils.http({ brotli: true }); let headers = { 'Accept-Encoding': 'br,gzip' }; try { - let res = await server.send('GET', '/not-compressed.txt', { headers }); - assert.is(res.headers['content-type'], 'text/plain'); - assert.is(res.headers['vary'], undefined); - assert.is(res.data, 'not-compressed.txt\n'); + let res = await server.send('GET', '/index.html', { headers }); + assert.is(res.headers['content-type'], 'text/html;charset=utf-8'); + assert.is(res.headers['vary'], 'Accept-Encoding'); + assert.is(res.data, 'brotli html\n'); assert.is(res.statusCode, 200); } finally { server.close(); @@ -850,6 +850,21 @@ brotli('should not set "Vary: Accept-Encoding" when a compressed file is request } }); +brotli('should not set "Vary: Accept-Encoding" when a compressed version of the requested file does not exist', async () => { + let server = utils.http({ brotli: true }); + let headers = { 'Accept-Encoding': 'br,gzip' }; + + try { + let res = await server.send('GET', '/no-compressed-version.txt', { headers }); + assert.is(res.headers['content-type'], 'text/plain'); + assert.is(res.headers['vary'], undefined); + assert.is(res.data, 'no-compressed-version.txt\n'); + assert.is(res.statusCode, 200); + } finally { + server.close(); + } +}); + brotli.run(); // --- @@ -915,15 +930,15 @@ gzip('should defer to brotli when "Accept-Encoding" allows both', async () => { } }); -gzip('should not set "Vary: Accept-Encoding" when a compressed version of the requested file does not exist', async () => { +gzip('should set "Vary: Accept-Encoding" when a compressed version of the requested file exists', async () => { let server = utils.http({ gzip: true }); let headers = { 'Accept-Encoding': 'br,gzip' }; try { - let res = await server.send('GET', '/not-compressed.txt', { headers }); - assert.is(res.headers['content-type'], 'text/plain'); - assert.is(res.headers['vary'], undefined); - assert.is(res.data, 'not-compressed.txt\n'); + let res = await server.send('GET', '/index.html', { headers }); + assert.is(res.headers['content-type'], 'text/html;charset=utf-8'); + assert.is(res.headers['vary'], 'Accept-Encoding'); + assert.is(res.data, 'gzip html\n'); assert.is(res.statusCode, 200); } finally { server.close(); @@ -945,6 +960,21 @@ gzip('should not set "Vary: Accept-Encoding" when a compressed file is requested } }); +gzip('should not set "Vary: Accept-Encoding" when a compressed version of the requested file does not exist', async () => { + let server = utils.http({ gzip: true }); + let headers = { 'Accept-Encoding': 'br,gzip' }; + + try { + let res = await server.send('GET', '/no-compressed-version.txt', { headers }); + assert.is(res.headers['content-type'], 'text/plain'); + assert.is(res.headers['vary'], undefined); + assert.is(res.data, 'no-compressed-version.txt\n'); + assert.is(res.statusCode, 200); + } finally { + server.close(); + } +}); + gzip.run(); // ---