Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

allow custom compression for custom Accept-Encoding Fixes #59 #62

Open
wants to merge 13 commits into
base: master
Choose a base branch
from
13 changes: 13 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -136,6 +136,19 @@ 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.

##### compressor

Allows you to specify your own compression stream for a given Content-Encoding.

```js
var opts = {
compressor: {
br: brotliStreamEncoder,
lzma: lzmaStreamEncoder,
},
};
```

#### .filter

The default `filter` function. This is used to construct a custom filter
Expand Down
19 changes: 15 additions & 4 deletions index.js
Original file line number Diff line number Diff line change
Expand Up @@ -173,7 +173,14 @@ function compression(options) {

// compression method
var accept = accepts(req)
var method = accept.encoding(['gzip', 'deflate', 'identity'])
var method = null;

// If we support a custom encoding and a custom encoding was requested
if (opts.compressor) {
method = accept.encoding(Object.keys(opts.compressor));
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

How would a used both define a custom encoding (like br), but yet still provide gzip encoding for clients that do not accept br? It looks like users will now need to provide their own gzip implementation to achieve this with this PR.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

heh, yep, just found this out the hard way, will patch

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Unfortunately it looks like there is still a bug here. The header Accept-Encoding: br;q=0.001, gzip, deflate will incorrectly use br over gzip just because the user wanted to provide an implementation for br.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ah, you're correct. I think I'll need to implement turning off gzip or deflate then. Maybe:

var opts = {
  compressor: {
    br: ...,
    gzip: null,
    deflate: null,
  }
};

} else {
method = accept.encoding(['gzip', 'deflate', 'identity']);
}

// we really don't prefer deflate
if (method === 'deflate' && accept.encoding(['gzip'])) {
Expand All @@ -188,9 +195,13 @@ function compression(options) {

// compression stream
debug('%s compression', method)
stream = method === 'gzip'
? zlib.createGzip(opts)
: zlib.createDeflate(opts)
if (method === 'gzip') {
stream = zlib.createGzip(opts);
} else if (method === 'deflate') {
stream = zlib.createDeflate(opts);
} else if (opts.compressor && method in opts.compressor) {
stream = opts.compressor[method];
}

// add bufferred listeners to stream
addListeners(stream, stream.on, listeners)
Expand Down
3 changes: 2 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,8 @@
"devDependencies": {
"istanbul": "0.3.21",
"mocha": "2.3.3",
"supertest": "1.1.0"
"supertest": "1.1.0",
"through": "2.3.8"
},
"files": [
"LICENSE",
Expand Down
39 changes: 39 additions & 0 deletions test/compression.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ var bytes = require('bytes');
var crypto = require('crypto');
var http = require('http');
var request = require('supertest');
var through = require('through');

var compression = require('..');

Expand Down Expand Up @@ -492,6 +493,44 @@ describe('compression()', function(){
})
})

describe('when "Accept-Encoding: custom"', function () {
it('should not use content encoding without a custom compressor function', function (done) {
var server = createServer({ threshold: 0 }, function (req, res) {
res.setHeader('Content-Type', 'text/plain')
res.end('hello, world')
})

request(server)
.get('/')
.set('Accept-Encoding', 'custom')
.expect(shouldNotHaveHeader('Content-Encoding'))
.expect(200, 'hello, world', done)
})

it('should use content encoding with a custom compressor function', function (done) {
var compressor = through(function (d) {
this.queue(d)
}, function () {
this.queue(null)
})
var opts = {
threshold: 0,
compressor: {
'bingo': compressor
}
}
var server = createServer(opts, function (req, res) {
res.setHeader('Content-Type', 'text/plain')
res.end('hello, world')
})

request(server)
.get('/')
.set('Accept-Encoding', 'bingo, gzip')
.expect('Content-Encoding', 'bingo', done)
})
})

describe('when "Cache-Control: no-transform" response header', function () {
it('should not compress response', function (done) {
var server = createServer({ threshold: 0 }, function (req, res) {
Expand Down