diff --git a/src/SecureStream.php b/src/SecureStream.php new file mode 100644 index 0000000..c185331 --- /dev/null +++ b/src/SecureStream.php @@ -0,0 +1,98 @@ +stream = $stream->stream; + $this->decorating = $stream; + $this->loop = $loop; + + $stream->on('error', function($error) { + $this->emit('error', [$error, $this]); + }); + $stream->on('end', function() { + $this->emit('end', [$this]); + }); + $stream->on('close', function() { + $this->emit('close', [$this]); + }); + $stream->on('drain', function() { + $this->emit('drain', [$this]); + }); + + $stream->pause(); + + $this->resume(); + } + + public function handleData($stream) + { + $data = stream_get_contents($stream); + + $this->emit('data', [$data, $this]); + + if (!is_resource($stream) || feof($stream)) { + $this->end(); + } + } + + public function pause() + { + $this->loop->removeReadStream($this->decorating->stream); + } + + public function resume() + { + if ($this->isReadable()) { + $this->loop->addReadStream($this->decorating->stream, [$this, 'handleData']); + } + } + + public function isReadable() + { + return $this->decorating->isReadable(); + } + + public function isWritable() + { + return $this->decorating->isWritable(); + } + + public function write($data) + { + return $this->decorating->write($data); + } + + public function close() + { + return $this->decorating->close(); + } + + public function end($data = null) + { + return $this->decorating->end($data); + } + + public function pipe(WritableStreamInterface $dest, array $options = array()) + { + Util::pipe($this, $dest, $options); + + return $dest; + } +} \ No newline at end of file diff --git a/src/StreamEncryption.php b/src/StreamEncryption.php index 84b2d28..d001130 100644 --- a/src/StreamEncryption.php +++ b/src/StreamEncryption.php @@ -18,10 +18,23 @@ class StreamEncryption private $errstr; private $errno; + + private $wrapSecure = false; public function __construct(LoopInterface $loop) { $this->loop = $loop; + + // See https://bugs.php.net/bug.php?id=65137 + // On versions affected by this bug we need to fread the stream until we + // get an empty string back because the buffer indicator could be wrong + if ( + PHP_VERSION_ID < 50433 + || (PHP_VERSION_ID >= 50500 && PHP_VERSION_ID < 50517) + || PHP_VERSION_ID === 50600 + ) { + $this->wrapSecure = true; + } } public function enable(Stream $stream) @@ -36,6 +49,10 @@ public function disable(Stream $stream) public function toggle(Stream $stream, $toggle) { + if (__NAMESPACE__ . '\SecureStream' === get_class($stream)) { + $stream = $stream->decorating; + } + // pause actual stream instance to continue operation on raw stream socket $stream->pause(); @@ -54,8 +71,13 @@ public function toggle(Stream $stream, $toggle) $this->loop->addReadStream($socket, $toggleCrypto); $toggleCrypto(); - return $deferred->promise()->then(function () use ($stream) { + return $deferred->promise()->then(function () use ($stream, $toggle) { + if ($toggle && $this->wrapSecure) { + return new SecureStream($stream, $this->loop); + } + $stream->resume(); + return $stream; }, function($error) use ($stream) { $stream->resume();