Skip to content

Commit 7258a76

Browse files
committed
Use EACCES error code if proxy uses 407 (Proxy Authentication Required)
1 parent 5db04ad commit 7258a76

File tree

3 files changed

+26
-5
lines changed

3 files changed

+26
-5
lines changed

README.md

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -295,7 +295,8 @@ $proxy = new ProxyConnector(
295295
connection attempt.
296296
If the authentication details are missing or not accepted by the remote HTTP
297297
proxy server, it is expected to reject each connection attempt with a
298-
`407` (Proxy Authentication Required) response status code.
298+
`407` (Proxy Authentication Required) response status code and an exception
299+
error code of `SOCKET_EACCES` (13).
299300

300301
#### Advanced secure proxy connections
301302

src/ProxyConnector.php

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -151,11 +151,14 @@ public function connect($uri)
151151
return;
152152
}
153153

154-
// status must be 2xx
155-
if ($response->getStatusCode() < 200 || $response->getStatusCode() >= 300) {
154+
if ($response->getStatusCode() === 407) {
155+
// map status code 407 (Proxy Authentication Required) to EACCES
156+
$deferred->reject(new RuntimeException('Proxy denied connection due to invalid authentication ' . $response->getStatusCode() . ' (' . $response->getReasonPhrase() . ') (EACCES)', defined('SOCKET_EACCES') ? SOCKET_EACCES : 13));
157+
return $stream->close();
158+
} elseif ($response->getStatusCode() < 200 || $response->getStatusCode() >= 300) {
159+
// map non-2xx status code to ECONNREFUSED
156160
$deferred->reject(new RuntimeException('Proxy refused connection with HTTP error code ' . $response->getStatusCode() . ' (' . $response->getReasonPhrase() . ') (ECONNREFUSED)', defined('SOCKET_ECONNREFUSED') ? SOCKET_ECONNREFUSED : 111));
157-
$stream->close();
158-
return;
161+
return $stream->close();
159162
}
160163

161164
// all okay, resolve with stream instance

tests/ProxyConnectorTest.php

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -208,6 +208,23 @@ public function testRejectsAndClosesIfStreamWritesTooMuchData()
208208
$promise->then(null, $this->expectCallableOnceWithExceptionCode(SOCKET_EMSGSIZE));
209209
}
210210

211+
public function testRejectsAndClosesIfStreamReturnsProyAuthenticationRequired()
212+
{
213+
$stream = $this->getMockBuilder('React\Socket\Connection')->disableOriginalConstructor()->setMethods(array('close', 'write'))->getMock();
214+
215+
$promise = \React\Promise\resolve($stream);
216+
$this->connector->expects($this->once())->method('connect')->willReturn($promise);
217+
218+
$proxy = new ProxyConnector('proxy.example.com', $this->connector);
219+
220+
$promise = $proxy->connect('google.com:80');
221+
222+
$stream->expects($this->once())->method('close');
223+
$stream->emit('data', array("HTTP/1.1 407 Proxy Authentication Required\r\n\r\n"));
224+
225+
$promise->then(null, $this->expectCallableOnceWithExceptionCode(SOCKET_EACCES));
226+
}
227+
211228
public function testRejectsAndClosesIfStreamReturnsNonSuccess()
212229
{
213230
$stream = $this->getMockBuilder('React\Socket\Connection')->disableOriginalConstructor()->setMethods(array('close', 'write'))->getMock();

0 commit comments

Comments
 (0)