9
9
"fmt"
10
10
"io"
11
11
"net/url"
12
- "strings "
12
+ "regexp "
13
13
14
14
"github.com/go-mysql-org/go-mysql/client"
15
15
"github.com/go-mysql-org/go-mysql/mysql"
@@ -23,12 +23,22 @@ var customTLSConfigMap = make(map[string]*tls.Config)
23
23
type driver struct {
24
24
}
25
25
26
- // Open: DSN user:password@addr[?db]
26
+ // Open: DSN
27
+ // Support both legacy style DSNs: user:password@addr[?db]
28
+ // And more standard DSNs: user:password@addr/db?param=value
29
+ // Optional parameters are supported in the standard DSN
27
30
func (d driver ) Open (dsn string ) (sqldriver.Conn , error ) {
28
- lastIndex := strings .LastIndex (dsn , "@" )
29
- seps := []string {dsn [:lastIndex ], dsn [lastIndex + 1 :]}
30
- if len (seps ) != 2 {
31
- return nil , errors .Errorf ("invalid dsn, must user:password@addr[[?db[¶m=X]]" )
31
+ // If a "/" occurs after "@" and then no more "@" or "/" occur after that
32
+ standardDSN , matchErr := regexp .MatchString ("@[^@]+/[^@/]+" , dsn )
33
+ if matchErr != nil {
34
+ return nil , errors .Errorf ("invalid dsn, must be user:password@addr[/db[?param=X]]" )
35
+ }
36
+
37
+ // Add a prefix so we can parse with url.Parse
38
+ dsn = "mysql://" + dsn
39
+ parsedDSN , parseErr := url .Parse (dsn )
40
+ if parseErr != nil {
41
+ return nil , errors .Errorf ("invalid dsn, must be user:password@addr[/db[?param=X]]" )
32
42
}
33
43
34
44
var user string
@@ -38,62 +48,38 @@ func (d driver) Open(dsn string) (sqldriver.Conn, error) {
38
48
var err error
39
49
var c * client.Conn
40
50
41
- if ss := strings .Split (seps [0 ], ":" ); len (ss ) == 2 {
42
- user , password = ss [0 ], ss [1 ]
43
- } else if len (ss ) == 1 {
44
- user = ss [0 ]
45
- } else {
46
- return nil , errors .Errorf ("invalid dsn, must user:password@addr[[?db[¶m=X]]" )
47
- }
48
-
49
- params := make (map [string ]string )
50
- if ss := strings .Split (seps [1 ], "?" ); len (ss ) == 2 {
51
- // If the dsn used a `/` for the path separator this would be easier to parse
52
- // with `url.Parse` and we could use `.Path` to get the db and then use
53
- // `Query()` to get the parameters and values.
54
- // But for consistency with the current way of doing things...
55
- addr = ss [0 ]
56
- dbAndParams := ss [1 ]
57
- if ss := strings .Split (dbAndParams , "&" ); len (ss ) == 1 {
58
- db = ss [0 ]
59
- } else {
60
- // We have to assume the first is the db
61
- // Then need to handle possible multiple parameters / query strings
62
- for i , p := range ss {
63
- if i == 0 {
64
- db = p
65
- } else {
66
- // Build key value pairs
67
- kv := strings .Split (p , "=" )
68
- params [kv [0 ]] = kv [1 ]
69
- }
51
+ user = parsedDSN .User .Username ()
52
+ // What does the below return for _. It's not err / bool
53
+ password , _ = parsedDSN .User .Password ()
54
+ addr = parsedDSN .Host
55
+ if standardDSN {
56
+ // Remove slash
57
+ db = parsedDSN .Path [1 :]
58
+ params := parsedDSN .Query ()
59
+ if params ["ssl" ] != nil {
60
+ tlsConfigName := params .Get ("ssl" )
61
+ switch tlsConfigName {
62
+ case "true" :
63
+ // This actually does insecureSkipVerify
64
+ // But not even sure if it makes sense to handle false? According to
65
+ // client_test.go it doesn't - it'd result in an error
66
+ c , err = client .Connect (addr , user , password , db , func (c * client.Conn ) { c .UseSSL (true ) })
67
+ case "custom" :
68
+ // I was too concerned about mimicking what go-sql-driver/mysql does which will
69
+ // allow any name for a custom tls profile and maps the query parameter value to
70
+ // that TLSConfig variable... there is no need to be that clever.
71
+ // Instead of doing that, let's store required custom TLSConfigs in a map that
72
+ // uses the DSN address as the key
73
+ c , err = client .Connect (addr , user , password , db , func (c * client.Conn ) { c .SetTLSConfig (customTLSConfigMap [addr ]) })
74
+ default :
75
+ return nil , errors .Errorf ("Supported options are ssl=true or ssl=custom" )
70
76
}
71
- }
72
- } else if len (ss ) == 1 {
73
- addr = ss [0 ]
74
- } else {
75
- return nil , errors .Errorf ("invalid dsn, must user:password@addr[[?db[¶m=X]]" )
76
- }
77
-
78
- tlsConfigName , tls := params ["ssl" ]
79
- if tls {
80
- switch tlsConfigName {
81
- case "true" :
82
- // This actually does insecureSkipVerify
83
- // But not even sure if it makes sense to handle false? According to
84
- // client_test.go it doesn't - it'd result in an error
85
- c , err = client .Connect (addr , user , password , db , func (c * client.Conn ) { c .UseSSL (true ) })
86
- case "custom" :
87
- // I was too concerned about mimicking what go-sql-driver/mysql does which will
88
- // allow any name for a custom tls profile and maps the query parameter value to
89
- // that TLSConfig variable... there is no need to be that clever.
90
- // Instead of doing that, let's store required custom TLSConfigs in a map that
91
- // uses the DSN address as the key
92
- c , err = client .Connect (addr , user , password , db , func (c * client.Conn ) { c .SetTLSConfig (customTLSConfigMap [addr ]) })
93
- default :
94
- return nil , errors .Errorf ("Supported options are ssl=true or ssl=custom" )
77
+ } else {
78
+ c , err = client .Connect (addr , user , password , db )
95
79
}
96
80
} else {
81
+ // No more processing here. Let's only support url parameters with the newer style DSN
82
+ db = parsedDSN .RawQuery
97
83
c , err = client .Connect (addr , user , password , db )
98
84
}
99
85
if err != nil {
0 commit comments