diff --git a/.travis.yml b/.travis.yml index df524d09..40df0040 100644 --- a/.travis.yml +++ b/.travis.yml @@ -10,8 +10,10 @@ node_js: - "5.12" - "6.14" - "7.10" + - "8.7" # Keep 8.7 around because it is the last minor on 8.x that didn't have http2 - "8.11" - "9.11" + - "10.11" sudo: false cache: directories: diff --git a/index.js b/index.js index f190c689..8557808e 100644 --- a/index.js +++ b/index.js @@ -81,7 +81,7 @@ function compression (options) { } if (!this._header) { - this._implicitHeader() + this.writeHead(this.statusCode) } return stream @@ -100,7 +100,7 @@ function compression (options) { length = chunkLength(chunk, encoding) } - this._implicitHeader() + this.writeHead(this.statusCode) } if (!stream) { diff --git a/test/compression.js b/test/compression.js index 013744cb..c087ede9 100644 --- a/test/compression.js +++ b/test/compression.js @@ -7,6 +7,16 @@ var http = require('http') var request = require('supertest') var zlib = require('zlib') +var describeHttp2 = describe.skip +try { + var http2 = require('http2') + describeHttp2 = describe +} catch (err) { + if (err) { + console.log('http2 tests disabled.') + } +} + var compression = require('..') describe('compression()', function () { @@ -301,6 +311,34 @@ describe('compression()', function () { .expect(200, done) }) + describeHttp2('http2', function () { + it('should work with http2 server', function (done) { + var server = createHttp2Server({ threshold: 0 }, function (req, res) { + res.setHeader('Content-Type', 'text/plain') + res.end('hello, world') + }) + server.on('listening', function () { + var client = createHttp2Client(server.address().port) + var request = client.request({ + 'Accept-Encoding': 'gzip' + }) + request.on('response', function (headers) { + assert.equal(headers['content-encoding'], 'gzip') + }) + request.on('error', function (error) { + console.error('An error event occurred on a http2 client request.', error) + }) + request.on('data', function (chunk) { + // no-op without which the request will stay open and cause a test timeout + }) + request.on('end', function () { + closeHttp2(request, client, server, done) + }) + request.end() + }) + }) + }) + describe('threshold', function () { it('should not compress responses below the threshold size', function (done) { var server = createServer({ threshold: '1kb' }, function (req, res) { @@ -661,6 +699,70 @@ function createServer (opts, fn) { }) } +function createHttp2Server (opts, fn) { + var _compression = compression(opts) + var server = http2.createServer(function (req, res) { + req.on('error', function (error) { + console.error('An error event occurred on a http2 request.', error) + }) + res.on('error', function (error) { + console.error('An error event occurred on a http2 response.', error) + }) + _compression(req, res, function (err) { + if (err) { + res.statusCode = err.status || 500 + res.end(err.message) + return + } + + fn(req, res) + }) + }) + server.on('error', function (error) { + console.error('An error event occurred on the http2 server.', error) + }) + server.on('sessionError', function (error) { + console.error('A sessionError event occurred on the http2 server.', error) + }) + server.listen(0, '127.0.0.1') + return server +} + +function createHttp2Client (port) { + var client = http2.connect('http://127.0.0.1:' + port) + client.on('error', function (error) { + console.error('An error event occurred in the http2 client stream.', error) + }) + return client +} + +function closeHttp2 (request, client, server, callback) { + if (typeof client.shutdown === 'function') { + // this is the node v8.x way of closing the connections + request.destroy(http2.constants.NGHTTP2_NO_ERROR, function () { + client.shutdown({}, function () { + server.close(function () { + callback() + }) + }) + }) + } else { + // this is the node v9.x onwards way of closing the connections + request.close(http2.constants.NGHTTP2_NO_ERROR, function () { + client.close(function () { + // force existing connections to time out after 1ms. + // this is done to force the server to close in some cases where it wouldn't do it otherwise. + server.setTimeout(1, function () { + console.warn('An http2 connection timed out instead of being closed properly.') + }) + server.close(function () { + callback() + }) + }) + }) + } +} + function shouldHaveBodyLength (length) { return function (res) { assert.equal(res.text.length, length, 'should have body length of ' + length)