1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
|
<?php
namespace gipfl\Protocol\NetString;
use gipfl\Protocol\Exception\ProtocolError;
use gipfl\Protocol\Generic\AbstractStreamWrapper;
class StreamWrapper extends AbstractStreamWrapper
{
protected $buffer = '';
protected $bufferLength = 0;
protected $bufferOffset = 0;
protected $expectedLength;
public function close()
{
// We might want to complain when buffer is not empty
$this->buffer = '';
$this->bufferLength = 0;
$this->bufferOffset = 0;
$this->expectedLength = null;
parent::close();
}
/**
* @param $data
*/
public function handleData($data)
{
$this->buffer .= $data;
$this->bufferLength += \strlen($data);
while ($this->bufferHasPacket()) {
$this->processNextPacket();
if ($this->bufferOffset !== 0) {
$this->buffer = \substr($this->buffer, $this->bufferOffset);
$this->bufferOffset = 0;
$this->bufferLength = \strlen($this->buffer);
}
}
}
public function write($data)
{
return $this->output->write(strlen($data) . ':' . $data . ',');
}
public function end($data = null)
{
if ($data !== null) {
$this->write($data);
}
$this->output->end();
}
/**
* @return bool
*/
protected function bufferHasPacket()
{
if ($this->expectedLength === null) {
if (false !== ($pos = \strpos(\substr($this->buffer, $this->bufferOffset, 10), ':'))) {
$lengthString = \ltrim(\substr($this->buffer, $this->bufferOffset, $pos), ',');
if (! \ctype_digit($lengthString)) {
$this->emit('error', [
new ProtocolError("Invalid length $lengthString")
]);
$this->close();
return false;
}
$this->expectedLength = (int) $lengthString;
$this->bufferOffset = $pos + 1;
} elseif ($this->bufferLength > ($this->bufferOffset + 10)) {
$this->throwInvalidBuffer();
$this->close();
return false;
} else {
return false;
}
}
return $this->bufferLength > ($this->bufferOffset + $this->expectedLength);
}
protected function processNextPacket()
{
$packet = \substr($this->buffer, $this->bufferOffset, $this->expectedLength);
$this->bufferOffset = $this->bufferOffset + $this->expectedLength;
$this->expectedLength = null;
$this->emit('data', [$packet]);
}
protected function throwInvalidBuffer()
{
$len = \strlen($this->buffer);
if ($len < 200) {
$debug = $this->buffer;
} else {
$debug = \substr($this->buffer, 0, 100)
. \sprintf('[..] truncated %d bytes [..] ', $len)
. \substr($this->buffer, -100);
}
$this->emit('error', [
new ProtocolError("Got invalid NetString data: $debug")
]);
}
}
|