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'); } 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/sirv.mjs b/tests/sirv.mjs index b18db63..4ffa072 100644 --- a/tests/sirv.mjs +++ b/tests/sirv.mjs @@ -820,6 +820,51 @@ brotli('should be preferred when "Accept-Encoding" allows both', 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', '/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(); + } +}); + +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(); + } +}); + +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(); // --- @@ -885,6 +930,51 @@ gzip('should defer to brotli when "Accept-Encoding" allows both', 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', '/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(); + } +}); + +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(); + } +}); + +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(); // ---