From fb8626fac0522f49fe29e2f4f686dfd8926204b6 Mon Sep 17 00:00:00 2001 From: Marcin Rataj Date: Fri, 26 Apr 2019 20:38:39 +0200 Subject: [PATCH] fix: ReadableStream detection in Chrome Apps Detection via `stream instanceof Stream` does not work correctly in browser context, especially when different polyfils are used and mixed together. This change replaces instanceof check with feature-detection of stream-like objects. It enables Hapi to be used in Chrome Apps (browser environments with additional chrome.sockets APIs) Real life example: https://github.com/ipfs-shipyard/ipfs-companion/issues/664 --- lib/response.js | 6 +++--- lib/streams.js | 10 ++++++++++ 2 files changed, 13 insertions(+), 3 deletions(-) diff --git a/lib/response.js b/lib/response.js index b85a791e0..52369e4f9 100755 --- a/lib/response.js +++ b/lib/response.js @@ -98,7 +98,7 @@ exports = module.exports = internals.Response = class { this.variety = 'buffer'; this._contentType = 'application/octet-stream'; } - else if (source instanceof Stream) { + else if (Streams.isReadableStream(source)) { this.variety = 'stream'; this._contentType = 'application/octet-stream'; } @@ -529,7 +529,7 @@ exports = module.exports = internals.Response = class { // Stream source - if (source instanceof Stream) { + if (Streams.isStream(source)) { if (typeof source._read !== 'function') { throw Boom.badImplementation('Stream must have a readable interface'); } @@ -607,7 +607,7 @@ exports = module.exports = internals.Response = class { } const stream = this._payload || this.source; - if (stream instanceof Stream) { + if (Streams.isReadableStream(stream)) { internals.Response.drain(stream); } } diff --git a/lib/streams.js b/lib/streams.js index 7b9dc4168..0b07f4dd8 100755 --- a/lib/streams.js +++ b/lib/streams.js @@ -7,6 +7,16 @@ const internals = { team: Symbol('team') }; +exports.isStream = stream => + stream !== null && + typeof stream === 'object' && + typeof stream.pipe === 'function'; + +exports.isReadableStream = stream => + exports.isStream(stream) && + stream.readable !== false && + typeof stream._read === 'function' && + typeof stream._readableState === 'object'; exports.drain = function (stream) {