@@ -29,6 +29,7 @@ type Limiter interface {
2929 ReportResult (result error )
3030}
3131
32+ // Options keeps the settings to setup redis connection.
3233type Options struct {
3334 // The network type, either tcp or unix.
3435 // Default is tcp.
@@ -187,23 +188,32 @@ func (opt *Options) clone() *Options {
187188}
188189
189190// 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>
190197func ParseURL (redisURL string ) (* Options , error ) {
191- o := & Options {Network : "tcp" }
192198 u , err := url .Parse (redisURL )
193199 if err != nil {
194200 return nil , err
195201 }
196202
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 )
199210 }
211+ }
200212
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 )
207217
208218 if len (u .Query ()) > 0 {
209219 return nil , errors .New ("no options supported" )
@@ -232,15 +242,52 @@ func ParseURL(redisURL string) (*Options, error) {
232242 return nil , fmt .Errorf ("invalid redis database number: %q" , f [0 ])
233243 }
234244 default :
235- return nil , errors . New ("invalid redis URL path: " + u .Path )
245+ return nil , fmt . Errorf ("invalid redis URL path: %s" , u .Path )
236246 }
237247
238248 if u .Scheme == "rediss" {
239249 o .TLSConfig = & tls.Config {ServerName : h }
240250 }
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+
241277 return o , nil
242278}
243279
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+
244291func newConnPool (opt * Options ) * pool.ConnPool {
245292 return pool .NewConnPool (& pool.Options {
246293 Dialer : func (ctx context.Context ) (net.Conn , error ) {
0 commit comments