diff --git a/src/WritableResourceStream.php b/src/WritableResourceStream.php index f43f95c..7e04205 100644 --- a/src/WritableResourceStream.php +++ b/src/WritableResourceStream.php @@ -23,8 +23,9 @@ public function __construct($stream, LoopInterface $loop, $writeBufferSoftLimit throw new \InvalidArgumentException('First parameter must be a valid stream resource'); } + // ensure resource is opened for writing (fopen mode must contain either of "waxc+") $meta = stream_get_meta_data($stream); - if (isset($meta['mode']) && str_replace(array('b', 't'), '', $meta['mode']) === 'r') { + if (isset($meta['mode']) && $meta['mode'] !== '' && strtr($meta['mode'], 'waxc+', '.....') === $meta['mode']) { throw new \InvalidArgumentException('Given stream resource is not opened in write mode'); } diff --git a/tests/DuplexResourceStreamTest.php b/tests/DuplexResourceStreamTest.php index 9ea43f9..6a57c5d 100644 --- a/tests/DuplexResourceStreamTest.php +++ b/tests/DuplexResourceStreamTest.php @@ -19,6 +19,21 @@ public function testConstructor() $conn = new DuplexResourceStream($stream, $loop); } + /** + * @covers React\Stream\DuplexResourceStream::__construct + */ + public function testConstructorWithExcessiveMode() + { + // excessive flags are ignored for temp streams, so we have to use a file stream + $name = tempnam(sys_get_temp_dir(), 'test'); + $stream = @fopen($name, 'r+eANYTHING'); + unlink($name); + + $loop = $this->createLoopMock(); + $buffer = new DuplexResourceStream($stream, $loop); + $buffer->close(); + } + /** * @covers React\Stream\DuplexResourceStream::__construct */ @@ -45,6 +60,21 @@ public function testConstructorThrowsExceptionOnWriteOnlyStream() new DuplexResourceStream(STDOUT, $loop); } + /** + * @covers React\Stream\DuplexResourceStream::__construct + * @expectedException InvalidArgumentException + */ + public function testConstructorThrowsExceptionOnWriteOnlyStreamWithExcessiveMode() + { + // excessive flags are ignored for temp streams, so we have to use a file stream + $name = tempnam(sys_get_temp_dir(), 'test'); + $stream = fopen($name, 'weANYTHING'); + unlink($name); + + $loop = $this->createLoopMock(); + new DuplexResourceStream($stream, $loop); + } + /** * @covers React\Stream\DuplexResourceStream::__construct */ diff --git a/tests/ReadableResourceStreamTest.php b/tests/ReadableResourceStreamTest.php index a6909ba..75afd05 100644 --- a/tests/ReadableResourceStreamTest.php +++ b/tests/ReadableResourceStreamTest.php @@ -18,6 +18,21 @@ public function testConstructor() new ReadableResourceStream($stream, $loop); } + /** + * @covers React\Stream\ReadableResourceStream::__construct + */ + public function testConstructorWithExcessiveMode() + { + // excessive flags are ignored for temp streams, so we have to use a file stream + $name = tempnam(sys_get_temp_dir(), 'test'); + $stream = @fopen($name, 'r+eANYTHING'); + unlink($name); + + $loop = $this->createLoopMock(); + $buffer = new ReadableResourceStream($stream, $loop); + $buffer->close(); + } + /** * @covers React\Stream\ReadableResourceStream::__construct */ @@ -44,6 +59,21 @@ public function testConstructorThrowsExceptionOnWriteOnlyStream() new ReadableResourceStream(STDOUT, $loop); } + /** + * @covers React\Stream\ReadableResourceStream::__construct + * @expectedException InvalidArgumentException + */ + public function testConstructorThrowsExceptionOnWriteOnlyStreamWithExcessiveMode() + { + // excessive flags are ignored for temp streams, so we have to use a file stream + $name = tempnam(sys_get_temp_dir(), 'test'); + $stream = fopen($name, 'weANYTHING'); + unlink($name); + + $loop = $this->createLoopMock(); + new ReadableResourceStream($stream, $loop); + } + /** * @covers React\Stream\ReadableResourceStream::__construct */ diff --git a/tests/WritableStreamResourceTest.php b/tests/WritableStreamResourceTest.php index 5f0400e..23da14b 100644 --- a/tests/WritableStreamResourceTest.php +++ b/tests/WritableStreamResourceTest.php @@ -19,6 +19,21 @@ public function testConstructor() $buffer->on('error', $this->expectCallableNever()); } + /** + * @covers React\Stream\WritableResourceStream::__construct + */ + public function testConstructorWithExcessiveMode() + { + // excessive flags are ignored for temp streams, so we have to use a file stream + $name = tempnam(sys_get_temp_dir(), 'test'); + $stream = @fopen($name, 'w+eANYTHING'); + unlink($name); + + $loop = $this->createLoopMock(); + $buffer = new WritableResourceStream($stream, $loop); + $buffer->close(); + } + /** * @covers React\Stream\WritableResourceStream::__construct * @expectedException InvalidArgumentException @@ -43,6 +58,21 @@ public function testConstructorThrowsExceptionOnReadOnlyStream() new WritableResourceStream($stream, $loop); } + /** + * @covers React\Stream\WritableResourceStream::__construct + * @expectedException InvalidArgumentException + */ + public function testConstructorThrowsExceptionOnReadOnlyStreamWithExcessiveMode() + { + // excessive flags are ignored for temp streams, so we have to use a file stream + $name = tempnam(sys_get_temp_dir(), 'test'); + $stream = fopen($name, 'reANYTHING'); + unlink($name); + + $loop = $this->createLoopMock(); + new WritableResourceStream($stream, $loop); + } + /** * @covers React\Stream\WritableResourceStream::__construct */