Skip to content

Commit 7052fe2

Browse files
committed
Add socket and SSL/TLS context options to connectors
1 parent 1cc368e commit 7052fe2

File tree

5 files changed

+88
-8
lines changed

5 files changed

+88
-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: 11 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -10,11 +10,13 @@ class SecureConnector implements ConnectorInterface
1010
{
1111
private $connector;
1212
private $streamEncryption;
13+
private $context;
1314

14-
public function __construct(ConnectorInterface $connector, LoopInterface $loop)
15+
public function __construct(ConnectorInterface $connector, LoopInterface $loop, array $context = array())
1516
{
1617
$this->connector = $connector;
1718
$this->streamEncryption = new StreamEncryption($loop);
19+
$this->context = $context;
1820
}
1921

2022
public function create($host, $port)
@@ -23,14 +25,17 @@ public function create($host, $port)
2325
return Promise\reject(new \BadMethodCallException('Encryption not supported on your platform (HHVM < 3.8?)'));
2426
}
2527

26-
return $this->connector->create($host, $port)->then(function (Stream $stream) use ($host) {
28+
$context = $this->context + array(
29+
'SNI_enabled' => true,
30+
'SNI_server_name' => $host,
31+
'peer_name' => $host
32+
);
33+
34+
return $this->connector->create($host, $port)->then(function (Stream $stream) use ($context) {
2735
// (unencrypted) TCP/IP connection succeeded
2836

2937
// set required SSL/TLS context options
30-
$resource = $stream->stream;
31-
stream_context_set_option($resource, 'ssl', 'SNI_enabled', true);
32-
stream_context_set_option($resource, 'ssl', 'SNI_server_name', $host);
33-
stream_context_set_option($resource, 'ssl', 'peer_name', $host);
38+
stream_context_set_option($stream->stream, array('ssl' => $context));
3439

3540
// try to enable encryption
3641
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 (false === $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
{
@@ -73,4 +74,45 @@ public function gettingEncryptedStuffFromGoogleShouldWork()
7374
$this->assertTrue($connected);
7475
$this->assertRegExp('#^HTTP/1\.0#', $response);
7576
}
77+
78+
/** @test */
79+
public function testSelfSignedRejectsIfVerificationIsEnabled()
80+
{
81+
$loop = new StreamSelectLoop();
82+
83+
$factory = new Factory();
84+
$dns = $factory->create('8.8.8.8', $loop);
85+
86+
87+
$secureConnector = new SecureConnector(
88+
new Connector($loop, $dns),
89+
$loop,
90+
array(
91+
'verify_peer' => true
92+
)
93+
);
94+
95+
$this->setExpectedException('RuntimeException');
96+
Block\await($secureConnector->create('self-signed.badssl.com', 443), $loop);
97+
}
98+
99+
/** @test */
100+
public function testSelfSignedResolvesIfVerificationIsDisabled()
101+
{
102+
$loop = new StreamSelectLoop();
103+
104+
$factory = new Factory();
105+
$dns = $factory->create('8.8.8.8', $loop);
106+
107+
$secureConnector = new SecureConnector(
108+
new Connector($loop, $dns),
109+
$loop,
110+
array(
111+
'verify_peer' => false
112+
)
113+
);
114+
115+
$conn = Block\await($secureConnector->create('self-signed.badssl.com', 443), $loop);
116+
$conn->close();
117+
}
76118
}

0 commit comments

Comments
 (0)