From dc81373cc9ad4ca1fd7c26e3d64f130d386ad29d Mon Sep 17 00:00:00 2001 From: Glen Mailer Date: Tue, 8 Sep 2015 22:22:36 +0100 Subject: [PATCH] Skip compression when response has Cache-Control: no-transform closes #51 closes #53 --- HISTORY.md | 1 + README.md | 4 ++++ index.js | 27 +++++++++++++++++++++++++++ test/compression.js | 32 ++++++++++++++++++++++++++++++++ 4 files changed, 64 insertions(+) diff --git a/HISTORY.md b/HISTORY.md index 23d65933..270e6d69 100644 --- a/HISTORY.md +++ b/HISTORY.md @@ -1,6 +1,7 @@ unreleased ========== + * Skip compression when response has `Cache-Control: no-transform` * deps: accepts@~1.3.0 - deps: mime-types@~2.1.7 - deps: negotiator@0.6.0 diff --git a/README.md b/README.md index 4d0abdff..a5d599db 100644 --- a/README.md +++ b/README.md @@ -31,6 +31,10 @@ Returns the compression middleware using the given `options`. The middleware will attempt to compress response bodies for all request that traverse through the middleware, based on the given `options`. +This middleware will never compress responses that include a `Cache-Control` +header with the [`no-transform` directive](https://tools.ietf.org/html/rfc7234#section-5.2.2.4), +as compressing will transform the body. + #### Options `compression()` accepts these properties in the options object. In addition to diff --git a/index.js b/index.js index 8848294d..acfc2a21 100644 --- a/index.js +++ b/index.js @@ -29,6 +29,13 @@ var zlib = require('zlib') module.exports = compression module.exports.filter = shouldCompress +/** + * Module variables. + * @private + */ + +var cacheControlNoTransformRegExp = /(?:^|,)\s*?no-transform\s*?(?:,|$)/ + /** * Compress response data with gzip / deflate. * @@ -135,6 +142,12 @@ function compression(options) { return } + // determine if the entity should be transformed + if (!shouldTransform(req, res)) { + nocompress('no transform') + return + } + // vary vary(res, 'Accept-Encoding') @@ -246,3 +259,17 @@ function shouldCompress(req, res) { return true } + +/** + * Determine if the entity should be transformed. + * @private + */ + +function shouldTransform(req, res) { + var cacheControl = res.getHeader('Cache-Control') + + // Don't compress for Cache-Control: no-transform + // https://tools.ietf.org/html/rfc7234#section-5.2.2.4 + return !cacheControl + || !cacheControlNoTransformRegExp.test(cacheControl) +} diff --git a/test/compression.js b/test/compression.js index 1efd4334..26e0ca26 100644 --- a/test/compression.js +++ b/test/compression.js @@ -492,6 +492,38 @@ describe('compression()', function(){ }) }) + describe('when "Cache-Control: no-transform" response header', function () { + it('should not compress response', function (done) { + var server = createServer({ threshold: 0 }, function (req, res) { + res.setHeader('Cache-Control', 'no-transform') + res.setHeader('Content-Type', 'text/plain') + res.end('hello, world') + }) + + request(server) + .get('/') + .set('Accept-Encoding', 'gzip') + .expect('Cache-Control', 'no-transform') + .expect(shouldNotHaveHeader('Content-Encoding')) + .expect(200, 'hello, world', done) + }) + + it('should not set Vary headerh', function (done) { + var server = createServer({ threshold: 0 }, function (req, res) { + res.setHeader('Cache-Control', 'no-transform') + res.setHeader('Content-Type', 'text/plain') + res.end('hello, world') + }) + + request(server) + .get('/') + .set('Accept-Encoding', 'gzip') + .expect('Cache-Control', 'no-transform') + .expect(shouldNotHaveHeader('Vary')) + .expect(200, done) + }) + }) + describe('.filter', function () { it('should be a function', function () { assert.equal(typeof compression.filter, 'function')