From ada7a5b1cc945508e1c322b43d2fd2cda80b4e6a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Christian=20L=C3=BCck?= Date: Tue, 14 Jun 2016 01:21:44 +0200 Subject: [PATCH] Fix processing events when input writes during data event This is a rare edge case that only triggered under these circumstances: * A control codes is in the middle of the buffer * A consumer listens for the data event * The consumer pushes data to the input stream during the event handler --- src/ControlCodeParser.php | 1 + tests/ControlCodeParserTest.php | 35 +++++++++++++++++++++++++++++++++ 2 files changed, 36 insertions(+) diff --git a/src/ControlCodeParser.php b/src/ControlCodeParser.php index 1721591..eb1a592 100644 --- a/src/ControlCodeParser.php +++ b/src/ControlCodeParser.php @@ -121,6 +121,7 @@ public function handleData($data) $this->buffer = substr($this->buffer, $c0); $this->emit('data', array($data)); + continue; } // C0 is now at start of buffer diff --git a/tests/ControlCodeParserTest.php b/tests/ControlCodeParserTest.php index c48cf5f..7b2cda3 100644 --- a/tests/ControlCodeParserTest.php +++ b/tests/ControlCodeParserTest.php @@ -87,6 +87,41 @@ public function testEmitsDataAndC0() $this->input->emit('data', array("hello world\n")); } + public function testEmitsDataInTwoChunksWithC0InBetween() + { + // first data event is everything before control code + $first = $this->expectCallableOnceWith('hello'); + $this->parser->once('data', $first); + + // second data event will fire with remaining buffer + $second = $this->expectCallableOnceWith('world'); + $parser = $this->parser; + $this->parser->once('data', function () use ($parser, $second) { + $parser->once('data', $second); + }); + + $this->input->emit('data', array("hello\nworld")); + } + + public function testEmitsDataInTwoChunkWithC0InBetweenWhileAddingDuringDataEvent() + { + // first data event is everything before control code + $first = $this->expectCallableOnceWith('hello'); + $this->parser->once('data', $first); + + // second data event will fire with remaining buffer + // we write to buffer while processing the first event and expect the full buffer + $second = $this->expectCallableOnceWith('worldagain'); + $input = $this->input; + $parser = $this->parser; + $this->parser->once('data', function () use ($input, $parser, $second) { + $parser->once('data', $second); + $input->emit('data', array('again')); + }); + + $this->input->emit('data', array("hello\nworld")); + } + public function testEmitsC0AndData() { $this->parser->on('data', $this->expectCallableOnceWith("hello world"));