8000 Merge pull request #70 from clue-labs/unix · SimonFrings/reactphp-redis@c59b033 · GitHub 8000
[go: up one dir, main page]

Skip to content

Commit c59b033

Browse files
authored
Merge pull request clue#70 from clue-labs/unix
Support communication over Unix domain sockets (UDS) via redis+unix://
2 parents 9188410 + 13b6898 commit c59b033

File tree

3 files changed

+60
-15
lines changed

3 files changed

+60
-15
lines changed

README.md

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -152,6 +152,20 @@ You can use the [standard](https://www.iana.org/assignments/uri-schemes/prov/red
152152
$factory->createClient('rediss://redis.example.com:6340');
153153
```
154154

155+
You can use the `redis+unix://` URI scheme if your Redis instance is listening
156+
on a Unix domain socket (UDS) path:
157+
158+
```php
159+
$factory->createClient('redis+unix:///tmp/redis.sock');
160+
161+
// the URI MAY contain `password` and `db` query parameters as seen above
162+
$factory->createClient('redis+unix:///tmp/redis.sock?password=secret&db=2');
163+
164+
// the URI MAY contain authentication details as userinfo as seen above
165+
// should be used with care, also note that database can not be passed as path
166+
$factory->createClient('redis+unix://:secret@/tmp/redis.sock');
167+
```
168+
155169
### Client
156170

157171
The `Client` is responsible for exchanging messages with Redis

src/Factory.php

Lines changed: 19 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -52,7 +52,7 @@ public function createClient($target)
5252

5353
$protocol = $this->protocol;
5454

55-
$promise = $this->connector->connect($parts['host'] . ':' . $parts['port'])->then(function (ConnectionInterface $stream) use ($protocol) {
55+
$promise = $this->connector->connect($parts['authority'])->then(function (ConnectionInterface $stream) use ($protocol) {
5656
return new StreamingClient($stream, $protocol->createResponseParser(), $protocol->createSerializer());
5757
});
5858

@@ -89,11 +89,18 @@ function ($error) use ($client) {
8989

9090
/**
9191
* @param string $target
92-
* @return array with keys host, port, auth and db
92+
* @return array with keys authority, auth and db
9393
* @throws InvalidArgumentException
9494
*/
9595
private function parseUrl($target)
9696
{
97+
$ret = array();
98+
// support `redis+unix://` scheme for Unix domain socket (UDS) paths
99+
if (preg_match('/^redis\+unix:\/\/([^:]*:[^@]*@)?(.+?)(\?.*)?$/', $target, $match)) {
100+
$ret['authority'] = 'unix://' . $match[2];
101+
$target = 'redis://' . (isset($match[1]) ? $match[1] : '') . 'localhost' . (isset($match[3]) ? $match[3] : '');
102+
}
103+
97104
if (strpos($target, '://') === false) {
98105
$target = 'redis://' . $target;
99106
}
@@ -103,38 +110,35 @@ private function parseUrl($target)
103110
throw new InvalidArgumentException('Given URL can not be parsed');
104111
}
105112

106-
if (!isset($parts['port'])) {
107-
$parts['port'] = 6379;
108-
}
109-
110113
if (isset($parts['pass'])) {
111-
$parts['auth'] = rawurldecode($parts['pass']);
114+
$ret['auth'] = rawurldecode($parts['pass']);
112115
}
113116

114117
if (isset($parts['path']) && $parts['path'] !== '') {
115118
// skip first slash
116-
$parts['db'] = substr($parts['path'], 1);
119+
$ret['db'] = substr($parts['path'], 1);
117120
}
118121

119-
if ($parts['scheme'] === 'rediss') {
120-
$parts['host'] = 'tls://' . $parts['host'];
122+
if (!isset($ret['authority'])) {
123+
$ret['authority'] =
124+
($parts['scheme'] === 'rediss' ? 'tls://' : '') .
125+
$parts['host'] . ':' .
126+
(isset($parts['port']) ? $parts['port'] : 6379);
121127
}
122128

123129
if (isset($parts['query'])) {
124130
$args = array();
125131
parse_str($parts['query'], $args);
126132

127133
if (isset($args['password'])) {
128-
$parts['auth'] = $args['password'];
134+
$ret['auth'] = $args['password'];
129135
}
130136

131137
if (isset($args['db'])) {
132-
$parts['db'] = $args['db'];
138+
$ret['db'] = $args['db'];
133139
}
134140
}
135141

136-
unset($parts['scheme'], $parts['user'], $parts['pass'], $parts['path']);
137-
138-
return $parts;
142+
return $ret;
139143
}
140144
}

tests/FactoryTest.php

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -107,6 +107,33 @@ public function testWillWriteAuthCommandIfRedissUriContainsUserInfo()
107107
$this->factory->createClient('rediss://hello:world@example.com');
108108
}
109109

110+
public function testWillWriteAuthCommandIfRedisUnixUriContainsPasswordQueryParameter()
111+
{
112+
$stream = $this->getMockBuilder('React\Socket\ConnectionInterface')->getMock();
113+
$stream->expects($this->once())->method('write')->with("*2\r\n$4\r\nauth\r\n$5\r\nworld\r\n");
114+
115+
$this->connector->expects($this->once())->method('connect')->with('unix:///tmp/redis.sock')->willReturn(Promise\resolve($stream));
116+
$this->factory->createClient('redis+unix:///tmp/redis.sock?password=world');
117+
}
118+
119+
public function testWillWriteAuthCommandIfRedisUnixUriContainsUserInfo()
120+
{
121+
$stream = $this->getMockBuilder('React\Socket\ConnectionInterface')->getMock();
122+
$stream->expects($this->once())->method('write')->with("*2\r\n$4\r\nauth\r\n$5\r\nworld\r\n");
123+
124+
$this->connector->expects($this->once())->method('connect')->with('unix:///tmp/redis.sock')->willReturn(Promise\resolve($stream));
125+
$this->factory->createClient('redis+unix://hello:world@/tmp/redis.sock');
126+
}
127+
128+
public function testWillWriteSelectCommandIfRedisUnixUriContainsDbQueryParameter()
129+
{
130+
$stream = $this->getMockBuilder('React\Socket\ConnectionInterface')->getMock();
131+
$stream->expects($this->once())->method('write')->with("*2\r\n$6\r\nselect\r\n$4\r\ndemo\r\n");
132+
133+
$this->connector->expects($this->once())->method('connect')->with('unix:///tmp/redis.sock')->willReturn(Promise\resolve($stream));
134+
$this->factory->createClient('redis+unix:///tmp/redis.sock?db=demo');
135+
}
136+
110137
public function testWillRejectIfConnectorRejects()
111138
{
112139
$this->connector->expects($this->once())->method(' 38D4 connect')->with('127.0.0.1:2')->willReturn(Promise\reject(new \RuntimeException()));

0 commit comments

Comments
 (0)
0