Skip to content

Commit 4aa5267

Browse files
committed
Preserve original errno and previous exception when using happy eyeballs
1 parent dd77705 commit 4aa5267

File tree

2 files changed

+42
-5
lines changed

2 files changed

+42
-5
lines changed

src/HappyEyeBallsConnectionBuilder.php

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -143,7 +143,11 @@ public function resolve($type, $reject)
143143
}
144144

145145
if ($that->hasBeenResolved() && $that->ipsCount === 0) {
146-
$reject(new \RuntimeException($that->error()));
146+
$reject(new \RuntimeException(
147+
$that->error(),
148+
0,
149+
$e
150+
));
147151
}
148152

149153
// Exception already handled above, so don't throw an unhandled rejection here
@@ -201,7 +205,11 @@ public function check($resolve, $reject)
201205
if ($that->ipsCount === $that->failureCount) {
202206
$that->cleanUp();
203207

204-
$reject(new \RuntimeException($that->error()));
208+
$reject(new \RuntimeException(
209+
$that->error(),
210+
$e->getCode(),
211+
$e
212+
));
205213
}
206214
});
207215

tests/HappyEyeBallsConnectionBuilderTest.php

Lines changed: 32 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -62,7 +62,11 @@ public function testConnectWillRejectWhenBothDnsLookupsReject()
6262
});
6363

6464
$this->assertInstanceOf('RuntimeException', $exception);
65+
assert($exception instanceof \RuntimeException);
66+
6567
$this->assertEquals('Connection to tcp://reactphp.org:80 failed during DNS lookup: DNS lookup error', $exception->getMessage());
68+
$this->assertEquals(0, $exception->getCode());
69+
$this->assertInstanceOf('RuntimeException', $exception->getPrevious());
6670
}
6771

6872
public function testConnectWillRejectWhenBothDnsLookupsRejectWithDifferentMessages()
@@ -98,7 +102,11 @@ public function testConnectWillRejectWhenBothDnsLookupsRejectWithDifferentMessag
98102
});
99103

100104
$this->assertInstanceOf('RuntimeException', $exception);
105+
assert($exception instanceof \RuntimeException);
106+
101107
$this->assertEquals('Connection to tcp://reactphp.org:80 failed during DNS lookup. Last error for IPv6: DNS6 error. Previous error for IPv4: DNS4 error', $exception->getMessage());
108+
$this->assertEquals(0, $exception->getCode());
109+
$this->assertInstanceOf('RuntimeException', $exception->getPrevious());
102110
}
103111

104112
public function testConnectWillStartDelayTimerWhenIpv4ResolvesAndIpv6IsPending()
@@ -468,15 +476,22 @@ public function testConnectWillRejectWhenOnlyTcp6ConnectionRejectsAndCancelNextA
468476
$builder = new HappyEyeBallsConnectionBuilder($loop, $connector, $resolver, $uri, $host, $parts);
469477

470478
$promise = $builder->connect();
471-
$deferred->reject(new \RuntimeException('Connection refused'));
479+
$deferred->reject(new \RuntimeException(
480+
'Connection refused',
481+
defined('SOCKET_ECONNREFUSED') ? SOCKET_ECONNREFUSED : 111
482+
));
472483

473484
$exception = null;
474485
$promise->then(null, function ($e) use (&$exception) {
475486
$exception = $e;
476487
});
477488

478489
$this->assertInstanceOf('RuntimeException', $exception);
490+
assert($exception instanceof \RuntimeException);
491+
479492
$this->assertEquals('Connection to tcp://reactphp.org:80 failed: Last error for IPv6: Connection refused. Previous error for IPv4: DNS failed', $exception->getMessage());
493+
$this->assertEquals(defined('SOCKET_ECONNREFUSED') ? SOCKET_ECONNREFUSED : 111, $exception->getCode());
494+
$this->assertInstanceOf('RuntimeException', $exception->getPrevious());
480495
}
481496

482497
public function testConnectWillRejectWhenOnlyTcp4ConnectionRejectsAndWillNeverStartNextAttemptTimer()
@@ -504,15 +519,22 @@ public function testConnectWillRejectWhenOnlyTcp4ConnectionRejectsAndWillNeverSt
504519
$builder = new HappyEyeBallsConnectionBuilder($loop, $connector, $resolver, $uri, $host, $parts);
505520

506521
$promise = $builder->connect();
507-
$deferred->reject(new \RuntimeException('Connection refused'));
522+
$deferred->reject(new \RuntimeException(
523+
'Connection refused',
524+
defined('SOCKET_ECONNREFUSED') ? SOCKET_ECONNREFUSED : 111
525+
));
508526

509527
$exception = null;
510528
$promise->then(null, function ($e) use (&$exception) {
511529
$exception = $e;
512530
});
513531

514532
$this->assertInstanceOf('RuntimeException', $exception);
533+
assert($exception instanceof \RuntimeException);
534+
515535
$this->assertEquals('Connection to tcp://reactphp.org:80 failed: Last error for IPv4: Connection refused. Previous error for IPv6: DNS failed', $exception->getMessage());
536+
$this->assertEquals(defined('SOCKET_ECONNREFUSED') ? SOCKET_ECONNREFUSED : 111, $exception->getCode());
537+
$this->assertInstanceOf('RuntimeException', $exception->getPrevious());
516538
}
517539

518540
public function testConnectWillRejectWhenAllConnectionsRejectAndCancelNextAttemptTimerImmediately()
@@ -542,15 +564,22 @@ public function testConnectWillRejectWhenAllConnectionsRejectAndCancelNextAttemp
542564
$builder = new HappyEyeBallsConnectionBuilder($loop, $connector, $resolver, $uri, $host, $parts);
543565

544566
$promise = $builder->connect();
545-
$deferred->reject(new \RuntimeException('Connection refused'));
567+
$deferred->reject(new \RuntimeException(
568+
'Connection refused',
569+
defined('SOCKET_ECONNREFUSED') ? SOCKET_ECONNREFUSED : 111
570+
));
546571

547572
$exception = null;
548573
$promise->then(null, function ($e) use (&$exception) {
549574
$exception = $e;
550575
});
551576

552577
$this->assertInstanceOf('RuntimeException', $exception);
578+
assert($exception instanceof \RuntimeException);
579+
553580
$this->assertEquals('Connection to tcp://reactphp.org:80 failed: Connection refused', $exception->getMessage());
581+
$this->assertEquals(defined('SOCKET_ECONNREFUSED') ? SOCKET_ECONNREFUSED : 111, $exception->getCode());
582+
$this->assertInstanceOf('RuntimeException', $exception->getPrevious());
554583
}
555584

556585
public function testConnectWillRejectWithMessageWithoutHostnameWhenAllConnectionsRejectAndCancelNextAttemptTimerImmediately()

0 commit comments

Comments
 (0)