@@ -29,6 +29,7 @@ type Limiter interface {
29
29
ReportResult (result error )
30
30
}
31
31
32
+ // Options keeps the settings to setup redis connection.
32
33
type Options struct {
33
34
// The network type, either tcp or unix.
34
35
// Default is tcp.
@@ -187,23 +188,32 @@ func (opt *Options) clone() *Options {
187
188
}
188
189
189
190
// ParseURL parses an URL into Options that can be used to connect to Redis.
191
+ // Scheme is required.
192
+ // There are two connection types: by tcp socket and by unix socket.
193
+ // Tcp connection:
194
+ // redis://<user>:<password>@<host>:<port>/<db_number>
195
+ // Unix connection:
196
+ // unix://<user>:<password>@</path/to/redis.sock>?db=<db_number>
190
197
func ParseURL (redisURL string ) (* Options , error ) {
191
- o := & Options {Network : "tcp" }
192
198
u , err := url .Parse (redisURL )
193
199
if err != nil {
194
200
return nil , err
195
201
}
196
202
197
- if u .Scheme != "redis" && u .Scheme != "rediss" {
198
- return nil , errors .New ("invalid redis URL scheme: " + u .Scheme )
203
+ switch u .Scheme {
204
+ case "redis" , "rediss" :
205
+ return setupTCPConn (u )
206
+ case "unix" :
207
+ return setupUnixConn (u )
208
+ default :
209
+ return nil , fmt .Errorf ("invalid redis URL scheme: %s" , u .Scheme )
199
210
}
211
+ }
200
212
201
- if u .User != nil {
202
- o .Username = u .User .Username ()
203
- if p , ok := u .User .Password (); ok {
204
- o .Password = p
205
- }
206
- }
213
+ func setupTCPConn (u * url.URL ) (* Options , error ) {
214
+ o := & Options {Network : "tcp" }
215
+
216
+ o .Username , o .Password = getUserPassword (u )
207
217
208
218
if len (u .Query ()) > 0 {
209
219
return nil , errors .New ("no options supported" )
@@ -232,15 +242,52 @@ func ParseURL(redisURL string) (*Options, error) {
232
242
return nil , fmt .Errorf ("invalid redis database number: %q" , f [0 ])
233
243
}
234
244
default :
235
- return nil , errors . New ("invalid redis URL path: " + u .Path )
245
+ return nil , fmt . Errorf ("invalid redis URL path: %s" , u .Path )
236
246
}
237
247
238
248
if u .Scheme == "rediss" {
239
249
o .TLSConfig = & tls.Config {ServerName : h }
240
250
}
251
+
252
+ return o , nil
253
+ }
254
+
255
+ func setupUnixConn (u * url.URL ) (* Options , error ) {
256
+ o := & Options {
257
+ Network : "unix" ,
258
+ }
259
+
260
+ if strings .TrimSpace (u .Path ) == "" { // path is required with unix connection
261
+ return nil , errors .New ("empty redis unix socket path" )
262
+ }
263
+ o .Addr = u .Path
264
+
265
+ o .Username , o .Password = getUserPassword (u )
266
+
267
+ dbStr := u .Query ().Get ("db" )
268
+ if dbStr == "" {
269
+ return o , nil // if database is not set, connect to 0 db.
270
+ }
271
+ db , err := strconv .Atoi (dbStr )
272
+ if err != nil {
273
+ return nil , fmt .Errorf ("invalid reids database number: %s" , err )
274
+ }
275
+ o .DB = db
276
+
241
277
return o , nil
242
278
}
243
279
280
+ func getUserPassword (u * url.URL ) (string , string ) {
281
+ var user , password string
282
+ if u .User != nil {
283
+ user = u .User .Username ()
284
+ if p , ok := u .User .Password (); ok {
285
+ password = p
286
+ }
287
+ }
288
+ return user , password
289
+ }
290
+
244
291
func newConnPool (opt * Options ) * pool.ConnPool {
245
292
return pool .NewConnPool (& pool.Options {
246
293
Dialer : func (ctx context.Context ) (net.Conn , error ) {
0 commit comments