10000 Improve DNS error messages and cancellation forwarding after DNS lookup by clue · Pull Request #170 · reactphp/socket · GitHub
[go: up one dir, main page]

Skip to content

Improve DNS error messages and cancellation forwarding after DNS lookup #170

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 3 commits into from
Aug 2, 2018
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Prev Previous commit
Work around possible cyclic garbage references in Exception trace
  • Loading branch information
clue committed Aug 1, 2018
commit e14f7bd3461f5cb25648231e85e78433b7cb4f70
4 changes: 4 additions & 0 deletions src/DnsConnector.php
Original file line number Diff line number Diff line change
Expand Up @@ -104,6 +104,10 @@ function ($_, $reject) use (&$promise, &$resolved, $uri) {

// (try to) cancel pending DNS lookup / connection attempt
if ($promise instanceof CancellablePromiseInterface) {
// 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;

$promise->cancel();
$promise = null;
}
Expand Down
30 changes: 29 additions & 1 deletion tests/DnsConnectorTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -242,6 +242,34 @@ public function testRejectionAfterDnsLookupShouldNotCreateAnyGarbageReferences()
$this->assertEquals(0, gc_collect_cycles());
}

/**
* @requires PHP 7
*/
public function testRejectionAfterDnsLookupShouldNotCreateAnyGarbageReferencesAgain()
{
if (class_exists('React\Promise\When')) {
$this->markTestSkipped('Not supported on legacy Promise v1 API');
}

gc_collect_cycles();

$dns = new Deferred();
$this->resolver->expects($this->once())->method('resolve')->with($this->equalTo('example.com'))->willReturn($dns->promise());

$tcp = new Deferred();
$dns->promise()->then(function () use ($tcp) {
$tcp->reject(new \RuntimeException('Connection failed'));
});
$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');
$dns->resolve('1.2.3.4');

unset($promise, $dns, $tcp);

$this->assertEquals(0, gc_collect_cycles());
}

/**
* @requires PHP 7
*/
Expand Down Expand Up @@ -289,7 +317,7 @@ public function testCancelDuringTcpConnectionShouldNotCreateAnyGarbageReferences
$dns->resolve('1.2.3.4');

$promise->cancel();
unset($promise, $dns);
unset($promise, $dns, $tcp);

$this->assertEquals(0, gc_collect_cycles());
}
Expand Down
38 changes: 37 additions & 1 deletion tests/IntegrationTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -184,7 +184,7 @@ function ($e) use (&$wait) {
/**
* @requires PHP 7
*/
public function testWaitingForConnectionTimeoutShouldNotCreateAnyGarbageReferences()
public function testWaitingForConnectionTimeoutDuringDnsLookupShouldNotCreateAnyGarbageReferences()
{
if (class_exists('React\Promise\When')) {
$this->markTestSkipped('Not supported on legacy Promise v1 API');
Expand Down Expand Up @@ -217,6 +217,42 @@ function ($e) use (&$wait) {
$this->assertEquals(0, gc_collect_cycles());
}

/**
* @requires PHP 7
*/
public function testWaitingForConnectionTimeoutDuringTcpConnectionShouldNotCreateAnyGarbageReferences()
{
if (class_exists('React\Promise\When')) {
$this->markTestSkipped('Not supported on legacy Promise v1 API');
}

$loop = Factory::create();
$connector = new Connector($loop, array('timeout' => 0.000001));

gc_collect_cycles();

$wait = true;
$promise = $connector->connect('8.8.8.8:53')->then(
null,
function ($e) use (&$wait) {
$wait = false;
throw $e;
}
);

// run loop for short period to ensure we detect connection timeout error
Block\sleep(0.01, $loop);
if ($wait) {
Block\sleep(0.2, $loop);
if ($wait) {
$this->fail('Connection attempt did not fail');
}
}
unset($promise);

$this->assertEquals(0, gc_collect_cycles());
}

public function testWaitingForInvalidDnsConnectionShouldNotCreateAnyGarbageReferences()
{
if (class_exists('React\Promise\When')) {
Expand Down
0