@@ -6,10 +6,13 @@ package nosql
6
6
7
7
import (
8
8
"crypto/tls"
9
+ "net/url"
9
10
"path"
10
11
"strconv"
11
12
"strings"
12
13
14
+ "code.gitea.io/gitea/modules/log"
15
+
13
16
"github.com/go-redis/redis/v8"
14
17
)
15
18
@@ -59,8 +62,59 @@ func (m *Manager) GetRedisClient(connection string) redis.UniversalClient {
59
62
name : []string {connection , uri .String ()},
60
63
}
61
64
65
+ opts := getRedisOptions (uri )
66
+ tlsConfig := getRedisTLSOptions (uri )
67
+
68
+ clientName := uri .Query ().Get ("clientname" )
69
+
70
+ if len (clientName ) > 0 {
71
+ client .name = append (client .name , clientName )
72
+ }
73
+
74
+ switch uri .Scheme {
75
+ case "redis+sentinels" :
76
+ fallthrough
77
+ case "rediss+sentinel" :
78
+ opts .TLSConfig = tlsConfig
79
+ fallthrough
80
+ case "redis+sentinel" :
81
+ client .UniversalClient = redis .NewFailoverClient (opts .Failover ())
82
+ case "redis+clusters" :
83
+ fallthrough
84
+ case "rediss+cluster" :
85
+ opts .TLSConfig = tlsConfig
86
+ fallthrough
87
+ case "redis+cluster" :
88
+ client .UniversalClient = redis .NewClusterClient (opts .Cluster ())
89
+ case "redis+socket" :
90
+ simpleOpts := opts .Simple ()
91
+ simpleOpts .Network = "unix"
92
+ simpleOpts .Addr = path .Join (uri .Host , uri .Path )
93
+ client .UniversalClient = redis .NewClient (simpleOpts )
94
+ case "rediss" :
95
+ opts .TLSConfig = tlsConfig
96
+ fallthrough
97
+ case "redis" :
98
+ client .UniversalClient = redis .NewClient (opts .Simple ())
99
+ default :
100
+ return nil
101
+ }
102
+
103
+ for _ , name := range client .name {
104
+ m .RedisConnections [name ] = client
105
+ }
106
+
107
+ client .count ++
108
+
109
+ return client
110
+ }
111
+
112
+ // getRedisOptions pulls various configuration options based on the RedisUri format and converts them to go-redis's
113
+ // UniversalOptions fields. This function explicitly excludes fields related to TLS configuration, which is
114
+ // conditionally attached to this options struct before being converted to the specific type for the redis scheme being
115
+ // used, and only in scenarios where TLS is applicable (e.g. rediss://, redis+clusters://).
116
+ func getRedisOptions (uri * url.URL ) * redis.UniversalOptions {
62
117
opts := & redis.UniversalOptions {}
63
- tlsConfig := & tls.Config {}
64
118
65
119
// Handle username/password
66
120
if password , ok := uri .User .Password (); ok {
@@ -131,75 +185,54 @@ func (m *Manager) GetRedisClient(connection string) redis.UniversalClient {
131
185
fallthrough
132
186
case "mastername" :
133
187
opts .MasterName = v [0 ]
134
- case "skipverify" :
135
- fallthrough
136
- case "insecureskipverify" :
137
- insecureSkipVerify , _ := strconv .ParseBool (v [0 ])
138
- tlsConfig .InsecureSkipVerify = insecureSkipVerify
139
- case "clientname" :
140
- client .name = append (client .name , v [0 ])
188
+ case "sentinelusername" :
189
+ opts .SentinelUsername = v [0 ]
190
+ case "sentinelpassword" :
191
+ opts .SentinelPassword = v [0 ]
141
192
}
142
193
}
143
194
144
- switch uri .Scheme {
145
- case "redis+sentinels" :
146
- fallthrough
147
- case "rediss+sentinel" :
148
- opts .TLSConfig = tlsConfig
149
- fallthrough
150
- case "redis+sentinel" :
151
- if uri .Host != "" {
152
- opts .Addrs = append (opts .Addrs , strings .Split (uri .Host , "," )... )
153
- }
154
- if uri .Path != "" {
155
- if db , err := strconv .Atoi (uri .Path [1 :]); err == nil {
156
- opts .DB = db
157
- }
158
- }
195
+ if uri .Host != "" {
196
+ opts .Addrs = append (opts .Addrs , strings .Split (uri .Host , "," )... )
197
+ }
159
198
160
- client .UniversalClient = redis .NewFailoverClient (opts .Failover ())
161
- case "redis+clusters" :
162
- fallthrough
163
- case "rediss+cluster" :
164
- opts .TLSConfig = tlsConfig
165
- fallthrough
166
- case "redis+cluster" :
167
- if uri .Host != "" {
168
- opts .Addrs = append (opts .Addrs , strings .Split (uri .Host , "," )... )
169
- }
170
- if uri .Path != "" {
171
- if db , err := strconv .Atoi (uri .Path [1 :]); err == nil {
172
- opts .DB = db
173
- }
199
+ // A redis connection string uses the path section of the URI in two different ways. In a TCP-based connection, the
200
+ // path will be a database index to automatically have the client SELECT. In a Unix socket connection, it will be the
201
+ // file path. We only want to try to coerce this to the database index when we're not expecting a file path so that
202
+ // the error log stays clean.
203
+ if uri .Path != "" && uri .Scheme != "redis+socket" {
204
+ if db , err := strconv .Atoi (uri .Path [1 :]); err == nil {
205
+ opts .DB = db
206
+ } else {
207
+ log .Error ("Provided database identifier '%s' is not a valid integer. Gitea will ignore this option." , uri .Path )
174
208
}
175
- client .UniversalClient = redis .NewClusterClient (opts .Cluster ())
176
- case "redis+socket" :
177
- simpleOpts := opts .Simple ()
178
- simpleOpts .Network = "unix"
179
- simpleOpts .Addr = path .Join (uri .Host , uri .Path )
180
- client .UniversalClient = redis .NewClient (simpleOpts )
181
- case "rediss" :
182
- opts .TLSConfig = tlsConfig
183
- fallthrough
184
- case "redis" :
185
- if uri .Host != "" {
186
- opts .Addrs = append (opts .Addrs , strings .Split (uri .Host , "," )... )
187
- }
188
- if uri .Path != "" {
189
- if db , err := strconv .Atoi (uri .Path [1 :]); err == nil {
190
- opts .DB = db
191
- }
192
- }
193
- client .UniversalClient = redis .NewClient (opts .Simple ())
194
- default :
195
- return nil
196
209
}
197
210
198
- for _ , name := range client .name {
199
- m .RedisConnections [name ] = client
211
+ return opts
212
+ }
213
+
214
+ // getRedisTlsOptions parses RedisUri TLS configuration parameters and converts them to the go TLS configuration
215
+ // equivalent fields.
216
+ func getRedisTLSOptions (uri * url.URL ) * tls.Config {
217
+ tlsConfig := & tls.Config {}
218
+
219
+ skipverify := uri .Query ().Get ("skipverify" )
220
+
221
+ if len (skipverify ) > 0 {
222
+ skipverify , err := strconv .ParseBool (skipverify )
223
+ if err != nil {
224
+ tlsConfig .InsecureSkipVerify = skipverify
225
+ }
200
226
}
201
227
202
- client . count ++
228
+ insecureskipverify := uri . Query (). Get ( "insecureskipverify" )
203
229
204
- return client
230
+ if len (insecureskipverify ) > 0 {
231
+ insecureskipverify , err := strconv .ParseBool (insecureskipverify )
232
+ if err != nil {
233
+ tlsConfig .InsecureSkipVerify = insecureskipverify
234
+ }
235
+ }
236
+
237
+ return tlsConfig
205
238
}
0 commit comments