Skip to content

Commit

Permalink
Forward compatibility with react/promise 3
Browse files Browse the repository at this point in the history
  • Loading branch information
WyriHaximus committed Jul 15, 2022
1 parent dd3c325 commit b93de58
Show file tree
Hide file tree
Showing 18 changed files with 130 additions and 103 deletions.
1 change: 1 addition & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ jobs:
name: PHPUnit (PHP ${{ matrix.php }} on ${{ matrix.os }})
runs-on: ${{ matrix.os }}
strategy:
fail-fast: false
matrix:
os:
- ubuntu-20.04
Expand Down
9 changes: 5 additions & 4 deletions composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -30,14 +30,14 @@
"evenement/evenement": "^3.0 || ^2.0 || ^1.0",
"react/dns": "^1.8",
"react/event-loop": "^1.2",
"react/promise": "^2.6.0 || ^1.2.1",
"react/promise-timer": "^1.8",
"react/promise": "^3@dev || ^2.6 || ^1.2.1",
"react/promise-timer": "^1.9",
"react/stream": "^1.2"
},
"require-dev": {
"clue/block-react": "^1.5",
"phpunit/phpunit": "^9.3 || ^5.7 || ^4.8.35",
"react/promise-stream": "^1.2"
"react/promise-stream": "^1.4"
},
"autoload": {
"psr-4": {
Expand All @@ -48,5 +48,6 @@
"psr-4": {
"React\\Tests\\Socket\\": "tests"
}
}
},
"minimum-stability": "dev"
}
3 changes: 1 addition & 2 deletions src/DnsConnector.php
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@

use React\Dns\Resolver\ResolverInterface;
use React\Promise;
use React\Promise\CancellablePromiseInterface;

final class DnsConnector implements ConnectorInterface
{
Expand Down Expand Up @@ -103,7 +102,7 @@ function ($_, $reject) use (&$promise, &$resolved, $uri) {
}

// (try to) cancel pending DNS lookup / connection attempt
if ($promise instanceof CancellablePromiseInterface) {
if ($promise instanceof Promise\PromiseInterface && \method_exists($promise, 'cancel')) {
// overwrite callback arguments for PHP7+ only, so they do not show
// up in the Exception trace and do not cause a possible cyclic reference.
$_ = $reject = null;
Expand Down
5 changes: 2 additions & 3 deletions src/HappyEyeBallsConnectionBuilder.php
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,6 @@
use React\EventLoop\LoopInterface;
use React\EventLoop\TimerInterface;
use React\Promise;
use React\Promise\CancellablePromiseInterface;

/**
* @internal
Expand Down Expand Up @@ -248,13 +247,13 @@ public function cleanUp()
$this->connectQueue = array();

foreach ($this->connectionPromises as $connectionPromise) {
if ($connectionPromise instanceof CancellablePromiseInterface) {
if ($connectionPromise instanceof Promise\PromiseInterface && \method_exists($connectionPromise, 'cancel')) {
$connectionPromise->cancel();
}
}

foreach ($this->resolverPromises as $resolverPromise) {
if ($resolverPromise instanceof CancellablePromiseInterface) {
if ($resolverPromise instanceof Promise\PromiseInterface && \method_exists($resolverPromise, 'cancel')) {
$resolverPromise->cancel();
}
}
Expand Down
19 changes: 11 additions & 8 deletions src/SecureConnector.php
Original file line number Diff line number Diff line change
Expand Up @@ -43,13 +43,14 @@ public function connect($uri)
$context = $this->context;
$encryption = $this->streamEncryption;
$connected = false;
/** @var array<\React\Promise\PromiseInterface> $promises */
$promises = array();
/** @var \React\Promise\PromiseInterface $promise */
$promise = $this->connector->connect(
$promise = $promises[] = $this->connector->connect(
\str_replace('tls://', '', $uri)
)->then(function (ConnectionInterface $connection) use ($context, $encryption, $uri, &$promise, &$connected) {
)->then(function (ConnectionInterface $connection) use ($context, $encryption, $uri, &$promises, &$connected) {
// (unencrypted) TCP/IP connection succeeded
$connected = true;

if (!$connection instanceof Connection) {
$connection->close();
throw new \UnexpectedValueException('Base connector does not use internal Connection class exposing stream resource');
Expand All @@ -61,7 +62,7 @@ public function connect($uri)
}

// try to enable encryption
return $promise = $encryption->enable($connection)->then(null, function ($error) use ($connection, $uri) {
return $promises[] = $encryption->enable($connection)->then(null, function ($error) use ($connection, $uri) {
// establishing encryption failed => close invalid connection and return error
$connection->close();

Expand Down Expand Up @@ -104,19 +105,21 @@ public function connect($uri)
});

return new \React\Promise\Promise(
function ($resolve, $reject) use ($promise) {
function ($resolve, $reject) use (&$promise) {
$promise->then($resolve, $reject);
},
function ($_, $reject) use (&$promise, $uri, &$connected) {
function ($_, $reject) use ($promise, &$promises, $uri, &$connected) {
if ($connected) {
$reject(new \RuntimeException(
'Connection to ' . $uri . ' cancelled during TLS handshake (ECONNABORTED)',
\defined('SOCKET_ECONNABORTED') ? \SOCKET_ECONNABORTED : 103
));
}

$promise->cancel();
$promise = null;
foreach ($promises as $promise) {
$promise->cancel();
}
$promises = array();
}
);
}
Expand Down
2 changes: 1 addition & 1 deletion src/StreamEncryption.php
Original file line number Diff line number Diff line change
Expand Up @@ -115,7 +115,7 @@ public function toggleCrypto($socket, Deferred $deferred, $toggle, $method)
\restore_error_handler();

if (true === $result) {
$deferred->resolve();
$deferred->resolve(null);
} else if (false === $result) {
// overwrite callback arguments for PHP7+ only, so they do not show
// up in the Exception trace and do not cause a possible cyclic reference.
Expand Down
22 changes: 11 additions & 11 deletions tests/DnsConnectorTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -26,47 +26,47 @@ public function setUpMocks()
public function testPassByResolverIfGivenIp()
{
$this->resolver->expects($this->never())->method('resolve');
$this->tcp->expects($this->once())->method('connect')->with($this->equalTo('127.0.0.1:80'))->will($this->returnValue(Promise\reject()));
$this->tcp->expects($this->once())->method('connect')->with($this->equalTo('127.0.0.1:80'))->will($this->returnValue(Promise\reject(new \Exception('reject'))));

$this->connector->connect('127.0.0.1:80');
}

public function testPassThroughResolverIfGivenHost()
{
$this->resolver->expects($this->once())->method('resolve')->with($this->equalTo('google.com'))->will($this->returnValue(Promise\resolve('1.2.3.4')));
$this->tcp->expects($this->once())->method('connect')->with($this->equalTo('1.2.3.4:80?hostname=google.com'))->will($this->returnValue(Promise\reject()));
$this->tcp->expects($this->once())->method('connect')->with($this->equalTo('1.2.3.4:80?hostname=google.com'))->will($this->returnValue(Promise\reject(new \Exception('reject'))));

$this->connector->connect('google.com:80');
}

public function testPassThroughResolverIfGivenHostWhichResolvesToIpv6()
{
$this->resolver->expects($this->once())->method('resolve')->with($this->equalTo('google.com'))->will($this->returnValue(Promise\resolve('::1')));
$this->tcp->expects($this->once())->method('connect')->with($this->equalTo('[::1]:80?hostname=google.com'))->will($this->returnValue(Promise\reject()));
$this->tcp->expects($this->once())->method('connect')->with($this->equalTo('[::1]:80?hostname=google.com'))->will($this->returnValue(Promise\reject(new \Exception('reject'))));

$this->connector->connect('google.com:80');
}

public function testPassByResolverIfGivenCompleteUri()
{
$this->resolver->expects($this->never())->method('resolve');
$this->tcp->expects($this->once())->method('connect')->with($this->equalTo('scheme://127.0.0.1:80/path?query#fragment'))->will($this->returnValue(Promise\reject()));
$this->tcp->expects($this->once())->method('connect')->with($this->equalTo('scheme://127.0.0.1:80/path?query#fragment'))->will($this->returnValue(Promise\reject(new \Exception('reject'))));

$this->connector->connect('scheme://127.0.0.1:80/path?query#fragment');
}

public function testPassThroughResolverIfGivenCompleteUri()
{
$this->resolver->expects($this->once())->method('resolve')->with($this->equalTo('google.com'))->will($this->returnValue(Promise\resolve('1.2.3.4')));
$this->tcp->expects($this->once())->method('connect')->with($this->equalTo('scheme://1.2.3.4:80/path?query&hostname=google.com#fragment'))->will($this->returnValue(Promise\reject()));
$this->tcp->expects($this->once())->method('connect')->with($this->equalTo('scheme://1.2.3.4:80/path?query&hostname=google.com#fragment'))->will($this->returnValue(Promise\reject(new \Exception('reject'))));

$this->connector->connect('scheme://google.com:80/path?query#fragment');
}

public function testPassThroughResolverIfGivenExplicitHost()
{
$this->resolver->expects($this->once())->method('resolve')->with($this->equalTo('google.com'))->will($this->returnValue(Promise\resolve('1.2.3.4')));
$this->tcp->expects($this->once())->method('connect')->with($this->equalTo('scheme://1.2.3.4:80/?hostname=google.de'))->will($this->returnValue(Promise\reject()));
$this->tcp->expects($this->once())->method('connect')->with($this->equalTo('scheme://1.2.3.4:80/?hostname=google.de'))->will($this->returnValue(Promise\reject(new \Exception('reject'))));

$this->connector->connect('scheme://google.com:80/?hostname=google.de');
}
Expand Down Expand Up @@ -288,7 +288,7 @@ public function testRejectionDuringDnsLookupShouldNotCreateAnyGarbageReferences(
$this->resolver->expects($this->once())->method('resolve')->with($this->equalTo('example.com'))->willReturn($dns->promise());
$this->tcp->expects($this->never())->method('connect');

$promise = $this->connector->connect('example.com:80');
$promise = $this->connector->connect('example.com:80')->then(null, function () { });
$dns->reject(new \RuntimeException('DNS failed'));
unset($promise, $dns);

Expand All @@ -309,7 +309,7 @@ public function testRejectionAfterDnsLookupShouldNotCreateAnyGarbageReferences()
$tcp = new Deferred();
$this->tcp->expects($this->once())->method('connect')->with($this->equalTo('1.2.3.4:80?hostname=example.com'))->willReturn($tcp->promise());

$promise = $this->connector->connect('example.com:80');
$promise = $this->connector->connect('example.com:80')->then(null, function () { });
$dns->resolve('1.2.3.4');
$tcp->reject(new \RuntimeException('Connection failed'));
unset($promise, $dns, $tcp);
Expand All @@ -334,7 +334,7 @@ public function testRejectionAfterDnsLookupShouldNotCreateAnyGarbageReferencesAg
});
$this->tcp->expects($this->once())->method('connect')->with($this->equalTo('1.2.3.4:80?hostname=example.com'))->willReturn($tcp->promise());

$promise = $this->connector->connect('example.com:80');
$promise = $this->connector->connect('example.com:80')->then(null, function () { });
$dns->resolve('1.2.3.4');

unset($promise, $dns, $tcp);
Expand All @@ -356,7 +356,7 @@ public function testCancelDuringDnsLookupShouldNotCreateAnyGarbageReferences()
$this->resolver->expects($this->once())->method('resolve')->with($this->equalTo('example.com'))->willReturn($dns->promise());
$this->tcp->expects($this->never())->method('connect');

$promise = $this->connector->connect('example.com:80');
$promise = $this->connector->connect('example.com:80')->then(null, function () { });

$promise->cancel();
unset($promise, $dns);
Expand All @@ -379,7 +379,7 @@ public function testCancelDuringTcpConnectionShouldNotCreateAnyGarbageReferences
});
$this->tcp->expects($this->once())->method('connect')->with($this->equalTo('1.2.3.4:80?hostname=example.com'))->willReturn($tcp);

$promise = $this->connector->connect('example.com:80');
$promise = $this->connector->connect('example.com:80')->then(function () { }, function () { });
$dns->resolve('1.2.3.4');

$promise->cancel();
Expand Down
2 changes: 1 addition & 1 deletion tests/FunctionalConnectorTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -143,7 +143,7 @@ public function testCancelPendingTlsConnectionDuringTlsHandshakeShouldCloseTcpCo
$deferred = new Deferred();
$server->on('connection', function (ConnectionInterface $connection) use ($promise, $deferred) {
$connection->on('close', function () use ($deferred) {
$deferred->resolve();
$deferred->resolve(null);
});

Loop::futureTick(function () use ($promise) {
Expand Down
16 changes: 12 additions & 4 deletions tests/FunctionalTcpServerTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,9 @@ public function testEmitsConnectionForNewConnection()
$server->on('connection', $this->expectCallableOnce());

$peer = new Promise(function ($resolve, $reject) use ($server) {
$server->on('connection', $resolve);
$server->on('connection', function () use ($resolve) {
$resolve(null);
});
});

$connector = new TcpConnector();
Expand Down Expand Up @@ -57,7 +59,9 @@ public function testConnectionForNewConnectionWhenResumedAfterPause()
$server->resume();

$peer = new Promise(function ($resolve, $reject) use ($server) {
$server->on('connection', $resolve);
$server->on('connection', function () use ($resolve) {
$resolve(null);
});
});

$connector = new TcpConnector();
Expand Down Expand Up @@ -207,7 +211,9 @@ public function testEmitsConnectionEvenIfClientConnectionIsCancelled()
$server->on('connection', $this->expectCallableOnce());

$peer = new Promise(function ($resolve, $reject) use ($server) {
$server->on('connection', $resolve);
$server->on('connection', function () use ($resolve) {
$resolve(null);
});
});

$connector = new TcpConnector();
Expand All @@ -232,7 +238,9 @@ public function testEmitsConnectionForNewIpv6Connection()
$server->on('connection', $this->expectCallableOnce());

$peer = new Promise(function ($resolve, $reject) use ($server) {
$server->on('connection', $resolve);
$server->on('connection', function () use ($resolve) {
$resolve(null);
});
});

$connector = new TcpConnector();
Expand Down
Loading

0 comments on commit b93de58

Please sign in to comment.