Skip to content

Commit 2795b0a

Browse files
committed
Merge pull request clue#36 from clue-labs/select
Consistent URI parsing, fixes host-only URIs sending SELECT
2 parents 8f1c9bb + 67ce0ee commit 2795b0a

File tree

2 files changed

+38
-44
lines changed

2 files changed

+38
-44
lines changed

src/Factory.php

Lines changed: 28 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -9,8 +9,6 @@
99
use React\SocketClient\Connector;
1010
use React\Dns\Resolver\Factory as ResolverFactory;
1111
use InvalidArgumentException;
12-
use BadMethodCallException;
13-
use Exception;
1412
use React\EventLoop\LoopInterface;
1513
use React\Promise;
1614

@@ -42,17 +40,21 @@ public function __construct(LoopInterface $loop, ConnectorInterface $connector =
4240
*/
4341
public function createClient($target = null)
4442
{
45-
$auth = $this->getAuthFromTarget($target);
46-
$db = $this->getDatabaseFromTarget($target);
43+
try {
44+
$parts = $this->parseUrl($target);
45+
} catch (InvalidArgumentException $e) {
46+
return Promise\reject($e);
47+
}
48+
4749
$protocol = $this->protocol;
4850

49-
$promise = $this->connect($target)->then(function (Stream $stream) use ($protocol) {
51+
$promise = $this->connector->create($parts['host'], $parts['port'])->then(function (Stream $stream) use ($protocol) {
5052
return new StreamingClient($stream, $protocol->createResponseParser(), $protocol->createSerializer());
5153
});
5254

53-
if ($auth !== null) {
54-
$promise = $promise->then(function (StreamingClient $client) use ($auth) {
55-
return $client->auth($auth)->then(
55+
if (isset($parts['auth'])) {
56+
$promise = $promise->then(function (StreamingClient $client) use ($parts) {
57+
return $client->auth($parts['auth'])->then(
5658
function () use ($client) {
5759
return $client;
5860
},
@@ -64,9 +66,9 @@ function ($error) use ($client) {
6466
});
6567
}
6668

67-
if ($db !== null) {
68-
$promise = $promise->then(function (StreamingClient $client) use ($db) {
69-
return $client->select($db)->then(
69+
if (isset($parts['db'])) {
70+
$promise = $promise->then(function (StreamingClient $client) use ($parts) {
71+
return $client->select($parts['db'])->then(
7072
function () use ($client) {
7173
return $client;
7274
},
@@ -81,6 +83,11 @@ function ($error) use ($client) {
8183
return $promise;
8284
}
8385

86+
/**
87+
* @param string|null $target
88+
* @return array with keys host, port, auth and db
89+
* @throws InvalidArgumentException
90+
*/
8491
private function parseUrl($target)
8592
{
8693
if ($target === null) {
@@ -92,54 +99,35 @@ private function parseUrl($target)
9299

93100
$parts = parse_url($target);
94101
if ($parts === false || !isset($parts['host']) || $parts['scheme'] !== 'tcp') {
95-
throw new Exception('Given URL can not be parsed');
102+
throw new InvalidArgumentException('Given URL can not be parsed');
96103
}
97104

98105
if (!isset($parts['port'])) {
99-
$parts['port'] = '6379';
106+
$parts['port'] = 6379;
100107
}
101108

102109
if ($parts['host'] === 'localhost') {
103110
$parts['host'] = '127.0.0.1';
104111
}
105112

106-
return $parts;
107-
}
108-
109-
private function connect($target)
110-
{
111-
try {
112-
$parts = $this->parseUrl($target);
113-
} catch (Exception $e) {
114-
return Promise\reject($e);
115-
}
116-
117-
return $this->connector->create($parts['host'], $parts['port']);
118-
}
119-
120-
private function getAuthFromTarget($target)
121-
{
122113
$auth = null;
123-
$parts = parse_url($target);
124114
if (isset($parts['user'])) {
125115
$auth = $parts['user'];
126116
}
127117
if (isset($parts['pass'])) {
128118
$auth .= ':' . $parts['pass'];
129119
}
120+
if ($auth !== null) {
121+
$parts['auth'] = $auth;
122+
}
130123

131-
return $auth;
132-
}
133-
134-
private function getDatabaseFromTarget($target)
135-
{
136-
$db = null;
137-
$path = parse_url($target, PHP_URL_PATH);
138-
if ($path !== null && $path !== '') {
124+
if (isset($parts['path']) && $parts['path'] !== '') {
139125
// skip first slash
140-
$db = substr($path, 1);
126+
$parts['db'] = substr($parts['path'], 1);
141127
}
142128

143-
return $db;
129+
unset($parts['scheme'], $parts['user'], $parts['pass'], $parts['path']);
130+
131+
return $parts;
144132
}
145133
}

tests/FactoryTest.php

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -23,25 +23,31 @@ public function testCtor()
2323
$this->factory = new Factory($this->loop);
2424
}
2525

26+
public function testWillConnectToLocalIpWithDefaultPortIfTargetIsNotGiven()
27+
{
28+
$this->connector->expects($this->once())->method('create')->with('127.0.0.1', 6379)->willReturn(Promise\reject(new \RuntimeException()));
29+
$this->factory->createClient();
30+
}
31+
2632
public function testWillConnectWithDefaultPort()
2733
{
2834
$this->connector->expects($this->once())->method('create')->with('redis.example.com', 6379)->willReturn(Promise\reject(new \RuntimeException()));
29-
$promise = $this->factory->createClient('redis.example.com');
35+
$this->factory->createClient('redis.example.com');
3036
}
3137

3238
public function testWillConnectToLocalIpWhenTargetIsLocalhost()
3339
{
3440
$this->connector->expects($this->once())->method('create')->with('127.0.0.1', 1337)->willReturn(Promise\reject(new \RuntimeException()));
35-
$promise = $this->factory->createClient('tcp://localhost:1337');
41+
$this->factory->createClient('tcp://localhost:1337');
3642
}
3743

3844
public function testWillResolveIfConnectorResolves()
3945
{
4046
$stream = $this->getMockBuilder('React\Stream\Stream')->disableOriginalConstructor()->getMock();
4147
$stream->expects($this->never())->method('write');
4248

43-
$this->connector->expects($this->once())->method('create')->with('127.0.0.1', 2)->willReturn(Promise\resolve($stream));
44-
$promise = $this->factory->createClient('tcp://127.0.0.1:2');
49+
$this->connector->expects($this->once())->method('create')->willReturn(Promise\resolve($stream));
50+
$promise = $this->factory->createClient();
4551

4652
$this->expectPromiseResolve($promise);
4753
}

0 commit comments

Comments
 (0)