diff --git a/HISTORY.md b/HISTORY.md index 3d224eda..d0c2c595 100644 --- a/HISTORY.md +++ b/HISTORY.md @@ -1,10 +1,10 @@ unreleased ========== * Use `res.headersSent` when available + * Add the enforceEncoding option for requests without `Accept-Encoding` header 1.7.5 / 2024-10-31 ========== - * deps: Replace accepts with negotiator@~0.6.4 - Add preference option * deps: bytes@3.1.2 diff --git a/README.md b/README.md index 55c19bfb..d32645e2 100644 --- a/README.md +++ b/README.md @@ -139,6 +139,12 @@ The default value is `zlib.Z_DEFAULT_WINDOWBITS`, or `15`. See [Node.js documentation](http://nodejs.org/api/zlib.html#zlib_memory_usage_tuning) regarding the usage. +##### enforceEncoding + +This is the default encoding to use when the client does not specify an encoding in the request's [Accept-Encoding](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Accept-Encoding) header. + +The default value is `identity`. + #### .filter The default `filter` function. This is used to construct a custom filter diff --git a/index.js b/index.js index 01b15bd5..dcefd817 100644 --- a/index.js +++ b/index.js @@ -37,6 +37,8 @@ module.exports.filter = shouldCompress var cacheControlNoTransformRegExp = /(?:^|,)\s*?no-transform\s*?(?:,|$)/ +var encodingSupported = ['*', 'gzip', 'deflate', 'identity'] + /** * Compress response data with gzip / deflate. * @@ -51,6 +53,7 @@ function compression (options) { // options var filter = opts.filter || shouldCompress var threshold = bytes.parse(opts.threshold) + var enforceEncoding = opts.enforceEncoding || 'identity' if (threshold == null) { threshold = 1024 @@ -177,6 +180,11 @@ function compression (options) { var negotiator = new Negotiator(req) var method = negotiator.encoding(['gzip', 'deflate', 'identity'], ['gzip']) + // if no method is found, use the default encoding + if (!req.headers['accept-encoding'] && encodingSupported.indexOf(enforceEncoding) !== -1) { + method = enforceEncoding === '*' ? 'gzip' : enforceEncoding + } + // negotiation failed if (!method || method === 'identity') { nocompress('not acceptable') diff --git a/test/compression.js b/test/compression.js index b6166eb1..61debb4a 100644 --- a/test/compression.js +++ b/test/compression.js @@ -702,6 +702,86 @@ describe('compression()', function () { .end() }) }) + + describe('enforceEncoding', function () { + it('should compress the provided encoding and not the default encoding', function (done) { + var server = createServer({ threshold: 0, enforceEncoding: 'deflate' }, function (req, res) { + res.setHeader('Content-Type', 'text/plain') + res.end('hello, world') + }) + + request(server) + .get('/') + .set('Accept-Encoding', 'gzip') + .expect('Content-Encoding', 'gzip') + .expect(200, 'hello, world', done) + }) + + it('should not compress when enforceEncoding is identity', function (done) { + var server = createServer({ threshold: 0, enforceEncoding: 'identity' }, function (req, res) { + res.setHeader('Content-Type', 'text/plain') + res.end('hello, world') + }) + + request(server) + .get('/') + .set('Accept-Encoding', '') + .expect(shouldNotHaveHeader('Content-Encoding')) + .expect(200, 'hello, world', done) + }) + + it('should compress when enforceEncoding is gzip', function (done) { + var server = createServer({ threshold: 0, enforceEncoding: 'gzip' }, function (req, res) { + res.setHeader('Content-Type', 'text/plain') + res.end('hello, world') + }) + + request(server) + .get('/') + .set('Accept-Encoding', '') + .expect('Content-Encoding', 'gzip') + .expect(200, 'hello, world', done) + }) + + it('should compress when enforceEncoding is deflate', function (done) { + var server = createServer({ threshold: 0, enforceEncoding: 'deflate' }, function (req, res) { + res.setHeader('Content-Type', 'text/plain') + res.end('hello, world') + }) + + request(server) + .get('/') + .set('Accept-Encoding', '') + .expect('Content-Encoding', 'deflate') + .expect(200, 'hello, world', done) + }) + + it('should not compress when enforceEncoding is unknown', function (done) { + var server = createServer({ threshold: 0, enforceEncoding: 'bogus' }, function (req, res) { + res.setHeader('Content-Type', 'text/plain') + res.end('hello, world') + }) + + request(server) + .get('/') + .set('Accept-Encoding', '') + .expect(shouldNotHaveHeader('Content-Encoding')) + .expect(200, 'hello, world', done) + }) + + it('should be gzip if no accept-encoding is sent when enforceEncoding is *', function (done) { + var server = createServer({ threshold: 0, enforceEncoding: '*' }, function (req, res) { + res.setHeader('Content-Type', 'text/plain') + res.end('hello, world') + }) + + request(server) + .get('/') + .set('Accept-Encoding', '') + .expect('Content-Encoding', 'gzip') + .expect(200, 'hello, world', done) + }) + }) }) function createServer (opts, fn) {