From 771422035929565fa775ccfb7f760388bb21a77e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jan=20Sch=C3=A4r?= Date: Tue, 29 Aug 2017 18:38:05 +0200 Subject: [PATCH 1/9] Fix tests on Windows --- package.json | 2 +- test/util.js | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/package.json b/package.json index 277bd74..b3da186 100644 --- a/package.json +++ b/package.json @@ -28,7 +28,7 @@ "scripts": { "lint": "jshint", "pretest": "npm run lint", - "test": "istanbul test _mocha -- --reporter spec --slow 500 --timeout 15000", + "test": "istanbul test node_modules/mocha/bin/_mocha -- --reporter spec --slow 500 --timeout 15000", "doc": "docco lib/* --output doc --layout parallel --template root.jst --css doc/docco.css && docco lib/protocol/* --output doc/protocol --layout parallel --template protocol.jst --css doc/docco.css" }, "repository": { diff --git a/test/util.js b/test/util.js index 4404da8..1a0862e 100644 --- a/test/util.js +++ b/test/util.js @@ -11,7 +11,7 @@ if (process.env.HTTP2_LOG) { if (process.stderr.isTTY) { var bin = path.resolve(path.dirname(require.resolve('bunyan')), '..', 'bin', 'bunyan'); if(bin && fs.existsSync(bin)) { - logOutput = spawn(bin, ['-o', 'short'], { + logOutput = spawn(process.execPath, [bin, '-o', 'short'], { stdio: [null, process.stderr, process.stderr] }).stdin; } From 3f7d200274df8f480e205f86f3770feb7cadf74b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jan=20Sch=C3=A4r?= Date: Tue, 29 Aug 2017 18:40:24 +0200 Subject: [PATCH 2/9] Fix changed error messages in tests --- test/flow.js | 4 ++-- test/stream.js | 4 ++-- test/util.js | 5 +++++ 3 files changed, 9 insertions(+), 4 deletions(-) diff --git a/test/flow.js b/test/flow.js index 2c025c1..ed67d4d 100644 --- a/test/flow.js +++ b/test/flow.js @@ -73,7 +73,7 @@ describe('flow.js', function() { flow._increaseWindow(Infinity); var increase = util.random(1,100); - expect(flow._increaseWindow.bind(flow, increase)).to.throw('Uncaught, unspecified "error" event.'); + expect(flow._increaseWindow.bind(flow, increase)).to.throw(util.uncaughtErrorEventMessage); }); it('should emit error when `_window` grows over the window limit', function() { var WINDOW_SIZE_LIMIT = Math.pow(2, 31) - 1; @@ -81,7 +81,7 @@ describe('flow.js', function() { flow._window = 0; flow._increaseWindow(WINDOW_SIZE_LIMIT); - expect(flow._increaseWindow.bind(flow, 1)).to.throw('Uncaught, unspecified "error" event.'); + expect(flow._increaseWindow.bind(flow, 1)).to.throw(util.uncaughtErrorEventMessage); }); }); diff --git a/test/stream.js b/test/stream.js index 9f0ee93..5540ceb 100644 --- a/test/stream.js +++ b/test/stream.js @@ -197,7 +197,7 @@ describe('stream.js', function() { stream.upstream.write({ type: 'HEADERS', headers:{}, flags: { END_STREAM: true }, count_change: util.noop }); example_frames.slice(2).forEach(function(invalid_frame) { invalid_frame.count_change = util.noop; - expect(stream._transition.bind(stream, false, invalid_frame)).to.throw('Uncaught, unspecified "error" event.'); + expect(stream._transition.bind(stream, false, invalid_frame)).to.throw(util.uncaughtErrorEventMessage); }); // CLOSED state as a result of outgoing END_STREAM @@ -207,7 +207,7 @@ describe('stream.js', function() { stream.end(); example_frames.slice(3).forEach(function(invalid_frame) { invalid_frame.count_change = util.noop; - expect(stream._transition.bind(stream, false, invalid_frame)).to.throw('Uncaught, unspecified "error" event.'); + expect(stream._transition.bind(stream, false, invalid_frame)).to.throw(util.uncaughtErrorEventMessage); }); }); it('should throw exception for invalid outgoing frames', function() { diff --git a/test/util.js b/test/util.js index 1a0862e..a50078b 100644 --- a/test/util.js +++ b/test/util.js @@ -89,3 +89,8 @@ exports.shuffleBuffers = function shuffleBuffers(buffers) { return output; }; +// Error message were changed in https://github.com/nodejs/node/commit/2141d374527337f7e1c74c9efad217b017d945cf +exports.uncaughtErrorEventMessage = + +(process.versions.node.split('.')[0]) >= 8 + ? 'Unhandled "error" event.' + : 'Uncaught, unspecified "error" event.' From ad68390d413b830120cc1fcd5e814b9b459f1a88 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jan=20Sch=C3=A4r?= Date: Tue, 29 Aug 2017 18:41:05 +0200 Subject: [PATCH 3/9] Fix http request test --- test/http.js | 1 + 1 file changed, 1 insertion(+) diff --git a/test/http.js b/test/http.js index e337293..293e827 100644 --- a/test/http.js +++ b/test/http.js @@ -724,6 +724,7 @@ describe('http.js', function() { host: 'localhost', port: 1259, path: '/', + method: 'POST', ca: serverOptions.cert }); request.write('Ping'); From dfc2f0142f1d320d432ca8bc7a317513d954ac8a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jan=20Sch=C3=A4r?= Date: Tue, 29 Aug 2017 18:42:25 +0200 Subject: [PATCH 4/9] Fix flow.js accessing internal buffers --- lib/protocol/flow.js | 18 ++++++++++++++---- 1 file changed, 14 insertions(+), 4 deletions(-) diff --git a/lib/protocol/flow.js b/lib/protocol/flow.js index 9529c0a..3ac1e06 100644 --- a/lib/protocol/flow.js +++ b/lib/protocol/flow.js @@ -200,10 +200,10 @@ Flow.prototype.read = function read(limit) { } // * Looking at the first frame in the queue without pulling it out if possible. - var frame = this._readableState.buffer[0]; + var frame = bufferHead(this._readableState.buffer); if (!frame && !this._readableState.ended) { this._read(); - frame = this._readableState.buffer[0]; + frame = bufferHead(this._readableState.buffer); } if (frame && (frame.type === 'DATA')) { @@ -297,8 +297,7 @@ Flow.prototype.push = function push(frame) { // `getLastQueuedFrame` returns the last frame in output buffers. This is primarily used by the // [Stream](stream.html) class to mark the last frame with END_STREAM flag. Flow.prototype.getLastQueuedFrame = function getLastQueuedFrame() { - var readableQueue = this._readableState.buffer; - return this._queue[this._queue.length - 1] || readableQueue[readableQueue.length - 1]; + return this._queue[this._queue.length - 1] || bufferTail(this._readableState.buffer); }; // Outgoing frames - managing the window size @@ -352,3 +351,14 @@ Flow.prototype.setInitialWindow = function setInitialWindow(initialWindow) { this._increaseWindow(initialWindow - this._initialWindow); this._initialWindow = initialWindow; }; + +// The node stream internal buffer was changed from an Array to a linked list in node v6.3.0 +function bufferHead (buffer) { + if ('head' in buffer) return buffer.head && buffer.head.data + return buffer[0] +} + +function bufferTail (buffer) { + if ('tail' in buffer) return buffer.tail && buffer.tail.data + return buffer[buffer.length - 1] +} From 656ec19ac5cedd1502d6af2c6d62129a0bdcfbe2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jan=20Sch=C3=A4r?= Date: Tue, 29 Aug 2017 23:27:53 +0200 Subject: [PATCH 5/9] Fix cleanup of old streams --- lib/protocol/connection.js | 32 ++++++++++++++++++++++++-------- test/http.js | 2 +- 2 files changed, 25 insertions(+), 9 deletions(-) diff --git a/lib/protocol/connection.js b/lib/protocol/connection.js index b0f156d..c6bd0d3 100644 --- a/lib/protocol/connection.js +++ b/lib/protocol/connection.js @@ -250,11 +250,26 @@ Connection.prototype.createStream = function createStream() { var stream = new Stream(this._log, this); this._allocatePriority(stream); - stream.on('end', this._removeStream.bind(this, stream)); + stream.on('state', this._streamStateChange.bind(this, stream)); return stream; }; +Connection.prototype._streamStateChange = function _removeStream(stream, state) { + if (state === 'CLOSED') { + if (!stream._closedByUs) { + this._removeStream(stream) + } else { + // An endpoint MUST ignore frames that it receives on closed streams after + // it has sent a RST_STREAM frame. An endpoint MAY choose to limit the + // period over which it ignores frames and treat frames that arrive after + // this time as being in error. + setTimeout(this._removeStream.bind(self, stream), 30000) // TODO: make timeout configurable + } + } +}; + + Connection.prototype._removeStream = function _removeStream(stream) { this._log.trace('Removing outbound stream.'); @@ -303,7 +318,7 @@ priority_loop: // 2. if there's no frame, skip this stream // 3. if forwarding this frame would make `streamCount` greater than `streamLimit`, skip // this stream - // 4. adding stream to the bucket of the next round unless it has ended + // 4. adding stream to the bucket of the next round // 5. assigning an ID to the frame (allocating an ID to the stream if there isn't already) // 6. if forwarding a PUSH_PROMISE, allocate ID to the promised stream // 7. forwarding the frame, changing `streamCount` as appropriate @@ -312,7 +327,6 @@ priority_loop: while (bucket.length > 0) { for (var index = 0; index < bucket.length; index++) { var stream = bucket[index]; - if(!stream || !stream.upstream) continue; var frame = stream.upstream.read((this._window > 0) ? this._window : -1); if (!frame) { @@ -322,11 +336,7 @@ priority_loop: continue; } - if (!stream._ended) { - nextBucket.push(stream); - } else { - delete this._streamIds[stream.id]; - } + nextBucket.push(stream); if (frame.stream === undefined) { frame.stream = stream.id || this._allocateId(stream); @@ -396,6 +406,12 @@ Connection.prototype._receive = function _receive(frame, done) { // * or creates one if it's not in `this.streams` if (!stream) { + if (frame.type === 'PRIORITY') { + // Priority frames can be sent on closed streams that have already been + // removed, or idle streams. Because priority dependencies are missing in + // this implementation anyway, these frames can simply be ignored. + return; + } stream = this._createIncomingStream(frame.stream); } diff --git a/test/http.js b/test/http.js index 293e827..ca0edec 100644 --- a/test/http.js +++ b/test/http.js @@ -300,7 +300,7 @@ describe('http.js', function() { }); } }); - }).timeout(15000); + }); }); describe('request with payload', function() { it('should work as expected', function(done) { From d748da084f27b55583194f2e32db528d4afe7212 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jan=20Sch=C3=A4r?= Date: Tue, 29 Aug 2017 23:28:23 +0200 Subject: [PATCH 6/9] Cleanup dependencies --- package.json | 20 +++++--------------- 1 file changed, 5 insertions(+), 15 deletions(-) diff --git a/package.json b/package.json index b3da186..e429323 100644 --- a/package.json +++ b/package.json @@ -6,24 +6,14 @@ "engines": { "node": ">=0.12.0" }, - "dependencies": { - "assert": "1.4.1", - "events": "1.1.1", - "https-browserify": "0.0.1", - "setimmediate": "^1.0.5", - "stream-browserify": "2.0.1", - "timers-browserify": "2.0.2", - "url": "^0.11.0", - "websocket-stream": "^5.0.1" - }, "devDependencies": { - "jshint": "*", - "istanbul": "*", + "bunyan": "^2.0.2", "chai": "*", - "mocha": "*", "docco": "*", - "browserify": "14.0.0 ", - "bunyan": "*" + "istanbul": "*", + "jshint": "*", + "mocha": "*", + "websocket-stream": "^5.0.1" }, "scripts": { "lint": "jshint", From c546acb14345ff9847a2ed002affb34fe2adef4d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jan=20Sch=C3=A4r?= Date: Tue, 29 Aug 2017 23:55:59 +0200 Subject: [PATCH 7/9] Fix whitespace Consistently use 2 space indentation --- .jshintignore | 2 +- .npmignore | 2 +- README.md | 2 +- lib/http.js | 42 ++++---- lib/protocol/connection.js | 2 +- lib/protocol/index.js | 12 +-- test/connection.js | 2 +- test/http.js | 216 ++++++++++++++++++------------------- 8 files changed, 139 insertions(+), 141 deletions(-) diff --git a/.jshintignore b/.jshintignore index 40b878d..c2658d7 100644 --- a/.jshintignore +++ b/.jshintignore @@ -1 +1 @@ -node_modules/ \ No newline at end of file +node_modules/ diff --git a/.npmignore b/.npmignore index 82e1e2d..5a34523 100644 --- a/.npmignore +++ b/.npmignore @@ -8,4 +8,4 @@ coverage .vscode/.browse* npm-debug.log typings -builds \ No newline at end of file +builds diff --git a/README.md b/README.md index ee38cbc..e1734be 100644 --- a/README.md +++ b/README.md @@ -12,7 +12,7 @@ Original Source and Fork intent This NodeJS `http2.js` module version is a fork of `node-http2` hosted on Github originally made by Gábor Molnár and available here: https://github.com/molnarg/node-http2 -This fork of `node-http2` module named `http2.js` starts at version `4.0.0` in case previous the repository decides to pick up work again on version `3.x.x`. +This fork of `node-http2` module named `http2.js` starts at version `4.0.0` in case previous the repository decides to pick up work again on version `3.x.x`. We are aware that node 8.4.0 now has experimental `http2` support via `--expose-http2`, and we will continue to support the full JavaScript implementation of `http2.js` at our discretion until HTTP/2 is more fully supported in a broad range of client platforms. diff --git a/lib/http.js b/lib/http.js index 953bd8a..67606da 100644 --- a/lib/http.js +++ b/lib/http.js @@ -348,8 +348,8 @@ IncomingMessage.prototype._validateHeaders = function _validateHeaders(headers) for (var i = 0; i < deprecatedHeaders.length; i++) { var key = deprecatedHeaders[i]; if (key in headers || (key === 'te' && headers[key] !== 'trailers')) { - this._log.error({ key: key, value: headers[key] }, 'Deprecated header found'); - this.stream.reset('PROTOCOL_ERROR'); + this._log.error({ key: key, value: headers[key] }, 'Deprecated header found'); + this.stream.reset('PROTOCOL_ERROR'); return; } } @@ -367,7 +367,7 @@ IncomingMessage.prototype._validateHeaders = function _validateHeaders(headers) if(headerNamePattern.test(headerName)) { this.stream.reset('PROTOCOL_ERROR'); return; - } + } } } }; @@ -411,13 +411,14 @@ OutgoingMessage.prototype._finish = function _finish() { this.once('socket', this._finish.bind(this)); } }; + OutgoingMessage.prototype.setHeader = function setHeader(name, value) { if (this.headersSent) { return this.emit('error', new Error('Can\'t set headers after they are sent.')); } else { name = name.toLowerCase(); if (deprecatedHeaders.indexOf(name) !== -1) { - return this.emit('error', new Error('Cannot set deprecated header: ' + name)); + return this.emit('error', new Error('Cannot set deprecated header: ' + name)); } this._headers[name] = value; } @@ -1016,25 +1017,25 @@ Agent.prototype.request = function request(options, callback) { endpoint.socket = options.transport; endpoint.socket.on('error', function (error) { - self._log.error('Socket error: ' + error.toString()); - request.emit('error', error); + self._log.error('Socket error: ' + error.toString()); + request.emit('error', error); }); endpoint.on('error', function(error){ - self._log.error('Connection error: ' + error.toString()); - request.emit('error', error); + self._log.error('Connection error: ' + error.toString()); + request.emit('error', error); }); endpoint.socket.on('close', function (error) { - // DPW This is sort of a hack to protect against - // the reuse of a endpoint that has the underlying - // connection closed. It would probably be better - // to implement this near lin 933 (if (key in this.endpoints)) - // by checking the endpoint state (requires new API to expose) - - // Alternatively, this could be a bug with my WS connection - // not emitting an error when it is unexpectedly closed ?? - delete self.endpoints[key]; + // DPW This is sort of a hack to protect against + // the reuse of a endpoint that has the underlying + // connection closed. It would probably be better + // to implement this near lin 933 (if (key in this.endpoints)) + // by checking the endpoint state (requires new API to expose) + + // Alternatively, this could be a bug with my WS connection + // not emitting an error when it is unexpectedly closed ?? + delete self.endpoints[key]; }); this.endpoints[key] = endpoint; @@ -1225,12 +1226,9 @@ OutgoingRequest.prototype._start = function _start(stream, options) { headers[':scheme'] = options.protocol.slice(0, -1); headers[':method'] = options.method; - if(options.port) - { + if (options.port) { headers[':authority'] = options.host + ':' + options.port; - } - else - { + } else { headers[':authority'] = options.host; } headers[':path'] = options.path; diff --git a/lib/protocol/connection.js b/lib/protocol/connection.js index c6bd0d3..04b2bde 100644 --- a/lib/protocol/connection.js +++ b/lib/protocol/connection.js @@ -300,7 +300,7 @@ Connection.prototype._send = function _send(immediate) { } else { if (!this._sendScheduled) { this._sendScheduled = true; - timers.setImmediate(this._send.bind(this, true)); + timers.setImmediate(this._send.bind(this, true)); } return; } diff --git a/lib/protocol/index.js b/lib/protocol/index.js index 46a079f..0d8f2a8 100644 --- a/lib/protocol/index.js +++ b/lib/protocol/index.js @@ -45,13 +45,13 @@ exports.Endpoint = require('./endpoint').Endpoint; exports.serializers = {}; var modules = ['./framer', './compressor', './flow', './connection', './stream', './endpoint']; try { - modules.map(require).forEach(function (module) { - for (var name in module.serializers) { - exports.serializers[name] = module.serializers[name]; - } - }); + modules.map(require).forEach(function (module) { + for (var name in module.serializers) { + exports.serializers[name] = module.serializers[name]; + } + }); } catch (e) { - // NOOP, probably in browser + // NOOP, probably in browser } diff --git a/test/connection.js b/test/connection.js index 1ab3b26..9cb58b9 100644 --- a/test/connection.js +++ b/test/connection.js @@ -52,7 +52,7 @@ describe('connection.js', function() { do { newPriority = randomPriority(); } while(newPriority === oldPriority); - + stream = { _priority: oldPriority }; connection._insert(stream, oldPriority); connection._reprioritize(stream, newPriority); diff --git a/test/http.js b/test/http.js index ca0edec..c06fc2c 100644 --- a/test/http.js +++ b/test/http.js @@ -393,126 +393,126 @@ describe('http.js', function() { }); }); describe('request over generic plain transport (example WebSocket)', function() { - it('should work as expected', function(done) { - var path = '/x'; - var message = 'Hello world'; - var portnum = 1239; - - var server = http2.raw.createServer({ - log: util.serverLog, - transport: function(options, start){ - var httpServer = http.createServer(); - options.server = httpServer; - var res = websocket.createServer(options, start); - res.listen = function(options, cb){ - httpServer.listen(options, cb); - }; - res.close = function (cb) { - httpServer.close(cb); - }; - return res; - } - }, function(request, response) { - expect(request.url).to.equal(path); - response.end(message); - }); - server.listen(portnum, function() { - var request = http2.raw.request({ - plain: true, - host: 'localhost', - port: portnum, - path: path, - transport: websocket('ws://localhost:' + portnum) - }, function(response) { - response.on('data', function(data) { - expect(data.toString()).to.equal(message); - server.close(); - done(); - }); - }); - request.end(); + it('should work as expected', function(done) { + var path = '/x'; + var message = 'Hello world'; + var portnum = 1239; + + var server = http2.raw.createServer({ + log: util.serverLog, + transport: function(options, start){ + var httpServer = http.createServer(); + options.server = httpServer; + var res = websocket.createServer(options, start); + res.listen = function(options, cb){ + httpServer.listen(options, cb); + }; + res.close = function (cb) { + httpServer.close(cb); + }; + return res; + } + }, function(request, response) { + expect(request.url).to.equal(path); + response.end(message); + }); + server.listen(portnum, function() { + var request = http2.raw.request({ + plain: true, + host: 'localhost', + port: portnum, + path: path, + transport: websocket('ws://localhost:' + portnum) + }, function(response) { + response.on('data', function(data) { + expect(data.toString()).to.equal(message); + server.close(); + done(); }); + }); + request.end(); }); + }); }); describe('get over plain generic transport (example WebSocket)', function() { - it('should work as expected', function(done) { - var path = '/x'; - var portnum = 1239; - var message = 'Hello world'; - - var server = http2.raw.createServer({ - log: util.serverLog, - transport: function(options, start){ - var httpServer = http.createServer(); - options.server = httpServer; - var res = websocket.createServer(options, start); - res.listen = function(options, cb){ - httpServer.listen(options, cb); - }; - res.close = function (cb) { - httpServer.close(cb); - }; - return res; - } - }, function(request, response) { - expect(request.url).to.equal(path); - response.end(message); - }); + it('should work as expected', function(done) { + var path = '/x'; + var portnum = 1239; + var message = 'Hello world'; - server.listen(portnum, function() { - var request = http2.raw.get({ - path: path, - transport: websocket('ws://localhost:' + portnum) - }, function(response) { - response.on('data', function(data) { - expect(data.toString()).to.equal(message); - server.close(); - done(); - }); - }); - request.end(); + var server = http2.raw.createServer({ + log: util.serverLog, + transport: function(options, start){ + var httpServer = http.createServer(); + options.server = httpServer; + var res = websocket.createServer(options, start); + res.listen = function(options, cb){ + httpServer.listen(options, cb); + }; + res.close = function (cb) { + httpServer.close(cb); + }; + return res; + } + }, function(request, response) { + expect(request.url).to.equal(path); + response.end(message); + }); + + server.listen(portnum, function() { + var request = http2.raw.get({ + path: path, + transport: websocket('ws://localhost:' + portnum) + }, function(response) { + response.on('data', function(data) { + expect(data.toString()).to.equal(message); + server.close(); + done(); }); + }); + request.end(); }); + }); }); - describe('get over plain generic transport (example WebSocket) 2', function() { - it('should work as expected', function(done) { - var path = '/x'; - var message = 'Hello world'; - - var server = http2.raw.createServer({ - log: util.serverLog, - transport: function(options, start){ - var httpServer = http.createServer(); - options.server = httpServer; - var res = websocket.createServer(options, start); - res.listen = function(options, cb){ - httpServer.listen(options, cb); - }; - res.close = function (cb) { - httpServer.close(cb); - }; - return res; - } - }, function(request, response) { - expect(request.url).to.equal(path); - response.end(message); - }); + describe('get over plain generic transport (example WebSocket) 2', function() { + it('should work as expected', function(done) { + var path = '/x'; + var message = 'Hello world'; - server.listen(1239, function() { - var request = http2.raw.get({path : path, transport: function(){ - return websocket('ws://localhost:' + 1239); - }}, function(response) { - response.on('data', function(data) { - expect(data.toString()).to.equal(message); - server.close(); - done(); - }); - }); - request.end(); - }); + var server = http2.raw.createServer({ + log: util.serverLog, + transport: function(options, start){ + var httpServer = http.createServer(); + options.server = httpServer; + var res = websocket.createServer(options, start); + res.listen = function(options, cb){ + httpServer.listen(options, cb); + }; + res.close = function (cb) { + httpServer.close(cb); + }; + return res; + } + }, function(request, response) { + expect(request.url).to.equal(path); + response.end(message); + }); + + server.listen(1239, function() { + var request = http2.raw.get({path: path, transport: function() { + return websocket('ws://localhost:' + 1239); + }}, function(response) { + response.on('data', function(data) { + expect(data.toString()).to.equal(message); + server.close(); + done(); + }); }); + request.end(); + }); }); + }); describe('request over plain TCP', function() { it('should work as expected', function(done) { var path = '/x'; From 111714ccf334582bc32f99a8b88808c0d3f94454 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jan=20Sch=C3=A4r?= Date: Tue, 29 Aug 2017 23:56:22 +0200 Subject: [PATCH 8/9] Fix hasValue --- lib/http.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/http.js b/lib/http.js index 67606da..cfe33ed 100644 --- a/lib/http.js +++ b/lib/http.js @@ -1168,7 +1168,7 @@ function unbundleSocket(socket) { } function hasValue(obj) { - return obj === null && obj === undefined; + return obj != null; } From af05f983e7a1677368645e0b56452a345ef618bf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jan=20Sch=C3=A4r?= Date: Tue, 29 Aug 2017 23:59:23 +0200 Subject: [PATCH 9/9] Enable Node.js 4, 6, 8 in travis.yml --- .travis.yml | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/.travis.yml b/.travis.yml index 35eaee4..dd338dd 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,8 +1,5 @@ language: node_js node_js: - "4" -# - "6" -# - "7" -script: mocha -env: - - COMMAND=test + - "6" + - "8"