From 0d73f8dde9fc7d518f477b8e04fe5abff1b33777 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 | 14 ++++++++++++++ 2 files changed, 17 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..8375956d1 100755 --- a/lib/streams.js +++ b/lib/streams.js @@ -7,6 +7,20 @@ const internals = { team: Symbol('team') }; +exports.isStream = function (stream) { + + return stream !== null && + typeof stream === 'object' && + typeof stream.pipe === 'function'; +}; + +exports.isReadableStream = function (stream) { + + return exports.isStream(stream) && + stream.readable !== false && + typeof stream._read === 'function' && + typeof stream._readableState === 'object'; +}; exports.drain = function (stream) {