Skip to content

Commit aae7eeb

Browse files
committed
Add socket and SSL/TLS context options to connectors
1 parent b468654 commit aae7eeb

File tree

5 files changed

+89
-8
lines changed

5 files changed

+89
-8
lines changed

README.md

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,16 @@ $tcpConnector->create('127.0.0.1', 80)->then(function (React\Stream\Stream $stre
4545
$loop->run();
4646
```
4747

48+
You can optionally pass additional
49+
[socket context options](http://php.net/manual/en/context.socket.php)
50+
to the constructor like this:
51+
52+
```php
53+
$tcpConnector = new React\SocketClient\TcpConnector($loop, array(
54+
'bindto' => '192.168.0.1:0'
55+
));
56+
```
57+
4858
Note that this class only allows you to connect to IP/port combinations.
4959
If you want to connect to hostname/port combinations, see also the following chapter.
5060

@@ -102,6 +112,17 @@ $secureConnector->create('www.google.com', 443)->then(function (React\Stream\Str
102112
$loop->run();
103113
```
104114

115+
You can optionally pass additional
116+
[SSL context options](http://php.net/manual/en/context.ssl.php)
117+
to the constructor like this:
118+
119+
```php
120+
$secureConnector = new React\SocketClient\SecureConnector($dnsConnector, $loop, array(
121+
'verify_peer' => false,
122+
'verify_peer_name' => false
123+
));
124+
```
125+
105126
### Unix domain sockets
106127

107128
Similarly, the `UnixConnector` class can be used to connect to Unix domain socket (UDS)

composer.json

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,5 +19,8 @@
1919
"branch-alias": {
2020
"dev-master": "0.4-dev"
2121
}
22+
},
23+
"require-dev": {
24+
"clue/block-react": "~1.0"
2225
}
2326
}

src/SecureConnector.php

Lines changed: 12 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -9,23 +9,29 @@ class SecureConnector implements ConnectorInterface
99
{
1010
private $connector;
1111
private $streamEncryption;
12+
private $context;
1213

13-
public function __construct(ConnectorInterface $connector, LoopInterface $loop)
14+
public function __construct(ConnectorInterface $connector, LoopInterface $loop, array $context = array())
1415
{
1516
$this->connector = $connector;
1617
$this->streamEncryption = new StreamEncryption($loop);
18+
$this->context = $context;
1719
}
1820

1921
public function create($host, $port)
2022
{
21-
return $this->connector->create($host, $port)->then(function (Stream $stream) use ($host) {
23+
$context = $this->context + array(
24+
'SNI_enabled' => true,
25+
'SNI_server_name' => $host,
26+
'CN_match' => $host,
27+
'peer_name' => $host
28+
);
29+
30+
return $this->connector->create($host, $port)->then(function (Stream $stream) use ($context) {
2231
// (unencrypted) TCP/IP connection succeeded
2332

2433
// set required SSL/TLS context options
25-
$resource = $stream->stream;
26-
stream_context_set_option($resource, 'ssl', 'SNI_enabled', true);
27-
stream_context_set_option($resource, 'ssl', 'SNI_server_name', $host);
28-
stream_context_set_option($resource, 'ssl', 'peer_name', $host);
34+
stream_context_set_option($stream->stream, array('ssl' => $context));
2935

3036
// try to enable encryption
3137
return $this->streamEncryption->enable($stream)->then(null, function ($error) use ($stream) {

src/TcpConnector.php

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,10 +11,12 @@
1111
class TcpConnector implements ConnectorInterface
1212
{
1313
private $loop;
14+
private $context;
1415

15-
public function __construct(LoopInterface $loop)
16+
public function __construct(LoopInterface $loop, array $context = array())
1617
{
1718
$this->loop = $loop;
19+
$this->context = $context;
1820
}
1921

2022
public function create($ip, $port)
@@ -25,7 +27,14 @@ public function create($ip, $port)
2527

2628
$url = $this->getSocketUrl($ip, $port);
2729

28-
$socket = stream_socket_client($url, $errno, $errstr, 0, STREAM_CLIENT_CONNECT | STREAM_CLIENT_ASYNC_CONNECT);
30+
$socket = stream_socket_client(
31+
$url,
32+
$errno,
33+
$errstr,
34+
0,
35+
STREAM_CLIENT_CONNECT | STREAM_CLIENT_ASYNC_CONNECT,
36+
stream_context_create(array('socket' => $this->context))
37+
);
2938

3039
if (!$socket) {
3140
return Promise\reject(new \RuntimeException(

tests/IntegrationTest.php

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
use React\SocketClient\Connector;
99
use React\SocketClient\SecureConnector;
1010
use React\Stream\BufferedSink;
11+
use Clue\React\Block;
1112

1213
class IntegrationTest extends TestCase
1314
{
@@ -69,4 +70,45 @@ public function gettingEncryptedStuffFromGoogleShouldWork()
6970
$this->assertTrue($connected);
7071
$this->assertRegExp('#^HTTP/1\.0#', $response);
7172
}
73+
74+
/** @test */
75+
public function testSelfSignedRejectsIfVerificationIsEnabled()
76+
{
77+
$loop = new StreamSelectLoop();
78+
79+
$factory = new Factory();
80+
$dns = $factory->create('8.8.8.8', $loop);
81+
82+
83+
$secureConnector = new SecureConnector(
84+
new Connector($loop, $dns),
85+
$loop,
86+
array(
87+
'verify_peer' => true
88+
)
89+
);
90+
91+
$this->setExpectedException('RuntimeException');
92+
Block\await($secureConnector->create('self-signed.badssl.com', 443), $loop);
93+
}
94+
95+
/** @test */
96+
public function testSelfSignedResolvesIfVerificationIsDisabled()
97+
{
98+
$loop = new StreamSelectLoop();
99+
100+
$factory = new Factory();
101+
$dns = $factory->create('8.8.8.8', $loop);
102+
103+
$secureConnector = new SecureConnector(
104+
new Connector($loop, $dns),
105+
$loop,
106+
array(
107+
'verify_peer' => false
108+
)
109+
);
110+
111+
$conn = Block\await($secureConnector->create('self-signed.badssl.com', 443), $loop);
112+
$conn->close();
113+
}
72114
}

0 commit comments

Comments
 (0)