Skip to content

Commit 5b9d87d

Browse files
committed
Only close stream when the we reached end of the stream
1 parent 2f39d05 commit 5b9d87d

File tree

4 files changed

+59
-2
lines changed

4 files changed

+59
-2
lines changed

src/DuplexResourceStream.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -191,7 +191,7 @@ public function handleData($stream)
191191

192192
if ($data !== '') {
193193
$this->emit('data', array($data));
194-
} else{
194+
} elseif (\feof($this->stream)) {
195195
// no data read => we reached the end and close the stream
196196
$this->emit('end');
197197
$this->close();

src/ReadableResourceStream.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -144,7 +144,7 @@ public function handleData()
144144

145145
if ($data !== '') {
146146
$this->emit('data', array($data));
147-
} else{
147+
} elseif (\feof($this->stream)) {
148148
// no data read => we reached the end and close the stream
149149
$this->emit('end');
150150
$this->close();

tests/DuplexResourceStreamIntegrationTest.php

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22

33
namespace React\Tests\Stream;
44

5+
use Clue\StreamFilter as Filter;
56
use React\Stream\DuplexResourceStream;
67
use React\Stream\ReadableResourceStream;
78
use React\EventLoop\ExtEventLoop;
@@ -342,6 +343,43 @@ public function testReadsNothingFromProcessPipeWithNoOutput($condition, $loopFac
342343
$loop->run();
343344
}
344345

346+
/**
347+
* @covers React\Stream\ReadableResourceStream::handleData
348+
* @dataProvider loopProvider
349+
*/
350+
public function testEmptyReadShouldntFcloseStream($condition, $loopFactory)
351+
{
352+
if (true !== $condition()) {
353+
return $this->markTestSkipped('Loop implementation not available');
354+
}
355+
356+
$server = stream_socket_server('tcp://127.0.0.1:0');
357+
358+
$client = stream_socket_client(stream_socket_get_name($server, false));
359+
$stream = stream_socket_accept($server);
360+
361+
362+
// add a filter which returns an error when encountering an 'a' when reading
363+
Filter\append($stream, function ($chunk) {
364+
return '';
365+
}, STREAM_FILTER_READ);
366+
367+
$loop = $loopFactory();
368+
369+
$conn = new DuplexResourceStream($stream, $loop);
370+
$conn->on('error', $this->expectCallableNever());
371+
$conn->on('data', $this->expectCallableNever());
372+
$conn->on('end', $this->expectCallableNever());
373+
374+
fwrite($client, "foobar\n");
375+
376+
$conn->handleData($stream);
377+
378+
fclose($stream);
379+
fclose($client);
380+
fclose($server);
381+
}
382+
345383
private function loopTick(LoopInterface $loop)
346384
{
347385
$loop->addTimer(0, function () use ($loop) {

tests/ReadableResourceStreamTest.php

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -365,6 +365,25 @@ public function testDataErrorShouldEmitErrorAndClose()
365365
$conn->handleData($stream);
366366
}
367367

368+
/**
369+
* @covers React\Stream\ReadableResourceStream::handleData
370+
*/
371+
public function testEmptyReadShouldntFcloseStream()
372+
{
373+
list($stream, $_) = stream_socket_pair(STREAM_PF_UNIX, STREAM_SOCK_STREAM, 0);
374+
$loop = $this->createLoopMock();
375+
376+
$conn = new ReadableResourceStream($stream, $loop);
377+
$conn->on('error', $this->expectCallableNever());
378+
$conn->on('data', $this->expectCallableNever());
379+
$conn->on('end', $this->expectCallableNever());
380+
381+
$conn->handleData();
382+
383+
fclose($stream);
384+
fclose($_);
385+
}
386+
368387
private function createLoopMock()
369388
{
370389
return $this->getMockBuilder('React\EventLoop\LoopInterface')->getMock();

0 commit comments

Comments
 (0)