Skip to content

Commit a7c1585

Browse files
committed
Import react/http-client v0.5.10
Change namespace from `React\HttpClient` to `React\Http\Client` and mark all classes as internal only. See https://github.com/reactphp/http-client for original repo.
1 parent a71880c commit a7c1585

13 files changed

Lines changed: 2300 additions & 32 deletions

composer.json

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,6 @@
88
"evenement/evenement": "^3.0 || ^2.0 || ^1.0",
99
"psr/http-message": "^1.0",
1010
"react/event-loop": "^1.0 || ^0.5",
11-
"react/http-client": "^0.5.10",
1211
"react/promise": "^2.3 || ^1.2.1",
1312
"react/promise-stream": "^1.1",
1413
"react/socket": "^1.1",
Lines changed: 207 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,207 @@
1+
<?php
2+
3+
namespace React\Http\Client;
4+
5+
use Evenement\EventEmitter;
6+
use Exception;
7+
use React\Stream\ReadableStreamInterface;
8+
use React\Stream\Util;
9+
use React\Stream\WritableStreamInterface;
10+
11+
/**
12+
* @internal
13+
*/
14+
class ChunkedStreamDecoder extends EventEmitter implements ReadableStreamInterface
15+
{
16+
const CRLF = "\r\n";
17+
18+
/**
19+
* @var string
20+
*/
21+
protected $buffer = '';
22+
23+
/**
24+
* @var int
25+
*/
26+
protected $remainingLength = 0;
27+
28+
/**
29+
* @var bool
30+
*/
31+
protected $nextChunkIsLength = true;
32+
33+
/**
34+
* @var ReadableStreamInterface
35+
*/
36+
protected $stream;
37+
38+
/**
39+
* @var bool
40+
*/
41+
protected $closed = false;
42+
43+
/**
44+
* @var bool
45+
*/
46+
protected $reachedEnd = false;
47+
48+
/**
49+
* @param ReadableStreamInterface $stream
50+
*/
51+
public function __construct(ReadableStreamInterface $stream)
52+
{
53+
$this->stream = $stream;
54+
$this->stream->on('data', array($this, 'handleData'));
55+
$this->stream->on('end', array($this, 'handleEnd'));
56+
Util::forwardEvents($this->stream, $this, array(
57+
'error',
58+
));
59+
}
60+
61+
/** @internal */
62+
public function handleData($data)
63+
{
64+
$this->buffer .= $data;
65+
66+
do {
67+
$bufferLength = strlen($this->buffer);
68+
$continue = $this->iterateBuffer();
69+
$iteratedBufferLength = strlen($this->buffer);
70+
} while (
71+
$continue &&
72+
$bufferLength !== $iteratedBufferLength &&
73+
$iteratedBufferLength > 0
74+
);
75+
76+
if ($this->buffer === false) {
77+
$this->buffer = '';
78+
}
79+
}
80+
81+
protected function iterateBuffer()
82+
{
83+
if (strlen($this->buffer) <= 1) {
84+
return false;
85+
}
86+
87+
if ($this->nextChunkIsLength) {
88+
$crlfPosition = strpos($this->buffer, static::CRLF);
89+
if ($crlfPosition === false && strlen($this->buffer) > 1024) {
90+
$this->emit('error', array(
91+
new Exception('Chunk length header longer then 1024 bytes'),
92+
));
93+
$this->close();
94+
return false;
95+
}
96+
if ($crlfPosition === false) {
97+
return false; // Chunk header hasn't completely come in yet
98+
}
99+
$lengthChunk = substr($this->buffer, 0, $crlfPosition);
100+
if (strpos($lengthChunk, ';') !== false) {
101+
list($lengthChunk) = explode(';', $lengthChunk, 2);
102+
}
103+
if ($lengthChunk !== '') {
104+
$lengthChunk = ltrim(trim($lengthChunk), "0");
105+
if ($lengthChunk === '') {
106+
// We've reached the end of the stream
107+
$this->reachedEnd = true;
108+
$this->emit('end');
109+
$this->close();
110+
return false;
111+
}
112+
}
113+
$this->nextChunkIsLength = false;
114+
if (dechex(@hexdec($lengthChunk)) !== strtolower($lengthChunk)) {
115+
$this->emit('error', array(
116+
new Exception('Unable to validate "' . $lengthChunk . '" as chunk length header'),
117+
));
118+
$this->close();
119+
return false;
120+
}
121+
$this->remainingLength = hexdec($lengthChunk);
122+
$this->buffer = substr($this->buffer, $crlfPosition + 2);
123+
return true;
124+
}
125+
126+
if ($this->remainingLength > 0) {
127+
$chunkLength = $this->getChunkLength();
128+
if ($chunkLength === 0) {
129+
return true;
130+
}
131+
$this->emit('data', array(
132+
substr($this->buffer, 0, $chunkLength),
133+
$this
134+
));
135+
$this->remainingLength -= $chunkLength;
136+
$this->buffer = substr($this->buffer, $chunkLength);
137+
return true;
138+
}
139+
140+
$this->nextChunkIsLength = true;
141+
$this->buffer = substr($this->buffer, 2);
142+
return true;
143+
}
144+
145+
protected function getChunkLength()
146+
{
147+
$bufferLength = strlen($this->buffer);
148+
149+
if ($bufferLength >= $this->remainingLength) {
150+
return $this->remainingLength;
151+
}
152+
153+
return $bufferLength;
154+
}
155+
156+
public function pause()
157+
{
158+
$this->stream->pause();
159+
}
160+
161+
public function resume()
162+
{
163+
$this->stream->resume();
164+
}
165+
166+
public function isReadable()
167+
{
168+
return $this->stream->isReadable();
169+
}
170+
171+
public function pipe(WritableStreamInterface $dest, array $options = array())
172+
{
173+
Util::pipe($this, $dest, $options);
174+
175+
return $dest;
176+
}
177+
178+
public function close()
179+
{
180+
$this->closed = true;
181+
return $this->stream->close();
182+
}
183+
184+
/** @internal */
185+
public function handleEnd()
186+
{
187+
$this->handleData('');
188+
189+
if ($this->closed) {
190+
return;
191+
}
192+
193+
if ($this->buffer === '' && $this->reachedEnd) {
194+
$this->emit('end');
195+
$this->close();
196+
return;
197+
}
198+
199+
$this->emit(
200+
'error',
201+
array(
202+
new Exception('Stream ended with incomplete control code')
203+
)
204+
);
205+
$this->close();
206+
}
207+
}

src/Client/Client.php

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
<?php
2+
3+
namespace React\Http\Client;
4+
5+
use React\EventLoop\LoopInterface;
6+
use React\Socket\ConnectorInterface;
7+
use React\Socket\Connector;
8+
9+
/**
10+
* @internal
11+
*/
12+
class Client
13+
{
14+
private $connector;
15+
16+
public function __construct(LoopInterface $loop, ConnectorInterface $connector = null)
17+
{
18+
if ($connector === null) {
19+
$connector = new Connector($loop);
20+
}
21+
22+
$this->connector = $connector;
23+
}
24+
25+
public function request($method, $url, array $headers = array(), $protocolVersion = '1.0')
26+
{
27+
$requestData = new RequestData($method, $url, $headers, $protocolVersion);
28+
29+
return new Request($this->connector, $requestData);
30+
}
31+
}

0 commit comments

Comments
 (0)