Skip to content

Commit

Permalink
Merge pull request #32 from graze/add-max-character-read
Browse files Browse the repository at this point in the history
Add max read characters
  • Loading branch information
brendankay authored Dec 11, 2020
2 parents b8091d6 + 87b9201 commit 543f5f0
Show file tree
Hide file tree
Showing 2 changed files with 69 additions and 8 deletions.
36 changes: 31 additions & 5 deletions src/TelnetClient.php
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,11 @@ class TelnetClient implements TelnetClientInterface
*/
protected $lineEnding = "\n";

/**
* @var int
*/
protected $maxBytesRead = 0;

/**
* @var Socket
*/
Expand Down Expand Up @@ -151,6 +156,16 @@ public function setLineEnding($lineEnding)
$this->lineEnding = $lineEnding;
}

/**
* Set the maximum number of bytes that can be read per request
*
* @param int $maxBytesRead
*/
public function setMaxBytesRead($maxBytesRead)
{
$this->maxBytesRead = $maxBytesRead;
}

/**
* @param Socket $socket
*/
Expand Down Expand Up @@ -225,23 +240,25 @@ protected function getResponse($prompt = null, $promptError = null)
{
$isError = false;
$buffer = '';
$bytesRead = 0;
do {
// process one character at a time
// process one byte at a time
try {
$character = $this->socket->read(1);
$byte = $this->socket->read(1);
$bytesRead++;
} catch (Exception $e) {
throw new TelnetException('failed reading from socket', 0, $e);
}

if (in_array($character, [$this->NULL, $this->DC1])) {
if (in_array($byte, [$this->NULL, $this->DC1])) {
break;
}

if ($this->interpretAsCommand->interpret($character, $this->socket)) {
if ($this->interpretAsCommand->interpret($byte, $this->socket)) {
continue;
}

$buffer .= $character;
$buffer .= $byte;

// check for prompt
if ($this->promptMatcher->isMatch($prompt ?: $this->prompt, $buffer, $this->lineEnding)) {
Expand All @@ -253,6 +270,15 @@ protected function getResponse($prompt = null, $promptError = null)
$isError = true;
break;
}

// throw an exception if the number of bytes read is greater than the limit
if ($this->maxBytesRead > 0 && $bytesRead >= $this->maxBytesRead) {
throw new TelnetException(sprintf(
'Maximum number of bytes read (%d), the last bytes were %s',
$this->maxBytesRead,
substr($buffer, -10)
));
}
} while (true);

return new TelnetResponse(
Expand Down
41 changes: 38 additions & 3 deletions tests/unit/TelnetClientTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -122,7 +122,7 @@ public function testExecute(
->with($command.$lineEnding)
->once();

// echo the command back when reading each character one-by-one from the socket
// echo the command back when reading each byte one-by-one from the socket
$commandResponse = str_split($command.$lineEnding.$promptResponse.$lineEnding);
$socket = $socket
->shouldReceive('read')
Expand Down Expand Up @@ -190,7 +190,7 @@ public function testExecutePromptError(
->with($command.$lineEnding)
->once();

// echo the command back when reading each character one-by-one from the socket
// echo the command back when reading each byte one-by-one from the socket
$commandResponse = str_split($command.$lineEnding.$promptResponse.$lineEnding);
$socket = $socket
->shouldReceive('read')
Expand Down Expand Up @@ -271,7 +271,7 @@ public function testWriteException()

public function testReadException()
{
$this->setExpectedException(TelnetExceptionInterface::class);
$this->setExpectedException(TelnetExceptionInterface::class, 'failed reading from socket');

$client = m::mock(TelnetClient::class)->makePartial();

Expand All @@ -286,6 +286,41 @@ public function testReadException()
$client->execute('aCommand');
}

public function testMaxBytesReadException()
{
$this->setExpectedException(
TelnetExceptionInterface::class,
'Maximum number of bytes read (20), the last bytes were 0123456789'
);

$socket = m::mock(Socket::class)
->shouldReceive('write')
->shouldReceive('close')
->shouldReceive('read');

call_user_func_array([$socket, 'andReturn'], str_split('0123456789012345678912'));
$socket = $socket->getMock();

$socketFactory = m::mock(SocketFactory::class)
->shouldReceive('createClient')
->andReturn($socket)
->once()
->getMock();

$promptMatcher = new PromptMatcher();

$interpretAsCommand = m::mock(InterpretAsCommand::class)
->shouldReceive('interpret')
->andReturn(false)
->getMock();

$client = new TelnetClient($socketFactory, $promptMatcher, $interpretAsCommand);
$client->connect('dsn');
$client->setMaxBytesRead(20);

$client->execute('aCommand');
}

public function testFactory()
{
$client = TelnetClient::factory();
Expand Down

0 comments on commit 543f5f0

Please sign in to comment.