diff --git a/README.md b/README.md index bcc4dcf..ec654cf 100644 --- a/README.md +++ b/README.md @@ -50,6 +50,22 @@ You can also establish your outgoing connections through a SOCKS proxy server by adding a dependency to [clue/socks-react](https://github.com/clue/php-socks-react). See the [SOCKS example](examples/socks). +### UNIX domain sockets + +This library also supports connecting to a local UNIX domain socket path. +You have to explicitly create a `Sender` that passes every request through the +given UNIX domain socket. +For consistency reasons you still have to pass full HTTP URLs for every request, +but the host and port will be ignored when establishing a connection. + +```php +$path = 'unix:///tmp/daemon.sock'; +$sender = Sender::createFromLoopUnix($loop, $path); +$client = new Browser($loop, $sender); + +$client->get('http://localhost/demo'); +``` + ## Install The recommended way to install this library is [through composer](http://getcomposer.org). [New to composer?](http://getcomposer.org/doc/00-intro.md) diff --git a/src/Io/Sender.php b/src/Io/Sender.php index 380197e..35c79b7 100644 --- a/src/Io/Sender.php +++ b/src/Io/Sender.php @@ -63,6 +63,20 @@ public static function createFromLoopConnectors(LoopInterface $loop, ConnectorIn return new self($http); } + /** + * create a sender that sends *everything* through given UNIX socket path + * + * @param LoopInterface $loop + * @param string $path + * @return self + */ + public static function createFromLoopUnix(LoopInterface $loop, $path) + { + $connector = new UnixConnector($loop, $path); + + return self::createFromLoopConnectors($loop, $connector); + } + private $http; public function __construct(HttpClient $http) diff --git a/src/Io/UnixConnector.php b/src/Io/UnixConnector.php new file mode 100644 index 0000000..455841f --- /dev/null +++ b/src/Io/UnixConnector.php @@ -0,0 +1,50 @@ +loop = $loop; + $this->path = $path; + } + + public function create($host, $port) + { + $deferred = new Deferred(); + + $resource = @stream_socket_client($this->path, $errno, $errstr, 1.0); + + if (!$resource) { + $deferred->reject(new RuntimeException('Unable to connect to unix domain socket path: ' . $errstr, $errno)); + } else { + $deferred->resolve(new Stream($resource, $this->loop)); + } + + return $deferred->promise(); + } +} diff --git a/tests/Io/SenderTest.php b/tests/Io/SenderTest.php index 13a1b4e..9600e0a 100644 --- a/tests/Io/SenderTest.php +++ b/tests/Io/SenderTest.php @@ -30,6 +30,13 @@ public function testCreateFromLoopConnectors() $this->assertInstanceOf('Clue\React\Buzz\Io\Sender', $sender); } + public function testCreateFromLoopUnix() + { + $sender = Sender::createFromLoopUnix($this->loop, 'unix:///run/daemon.sock'); + + $this->assertInstanceOf('Clue\React\Buzz\Io\Sender', $sender); + } + public function testSenderRejection() { $connector = $this->getMock('React\SocketClient\ConnectorInterface'); diff --git a/tests/Io/UnixConnectorTest.php b/tests/Io/UnixConnectorTest.php new file mode 100644 index 0000000..74b6a80 --- /dev/null +++ b/tests/Io/UnixConnectorTest.php @@ -0,0 +1,41 @@ +getMock('React\EventLoop\LoopInterface'); + $connector = new UnixConnector($loop, $path); + + $promise = $connector->create('localhost', 80); + + $this->expectPromiseReject($promise); + } + + public function testValid() + { + $path = tempnam(sys_get_temp_dir(), 'socket'); + + $server = @stream_socket_server('unix://' . $path, $errno, $errstr); + + if (!$server) { + $this->markTestSkipped('Unable to create socket: ' . $errstr . '(' . $errno .')'); + return; + } + + $loop = $this->getMock('React\EventLoop\LoopInterface'); + $connector = new UnixConnector($loop, 'unix://' . $path); + + $promise = $connector->create('localhost', 80); + + $this->expectPromiseResolve($promise); + + fclose($server); + unlink($path); + } +}