func ParseURL(mod mb.Module, rawURL string) (mb.HostData, error) { c := struct { Username string `config:"username"` Password string `config:"password"` }{} if err := mod.UnpackConfig(&c); err != nil { return mb.HostData{}, err } if parts := strings.SplitN(rawURL, "://", 2); len(parts) != 2 { // Add scheme. rawURL = fmt.Sprintf("postgres://%s", rawURL) } u, err := url.Parse(rawURL) if err != nil { return mb.HostData{}, fmt.Errorf("error parsing URL: %v", err) } parse.SetURLUser(u, c.Username, c.Password) if timeout := mod.Config().Timeout; timeout > 0 { q := u.Query() q.Set("connect_timeout", strconv.Itoa(int(timeout.Seconds()))) u.RawQuery = q.Encode() } // https://www.postgresql.org/docs/current/static/libpq-connect.html#LIBPQ-CONNSTRING connString, err := pq.ParseURL(u.String()) if err != nil { return mb.HostData{}, err } h := parse.NewHostDataFromURL(u) // Store the connection string instead of URL to avoid the cost of sql.Open // parsing the URL on each call. h.URI = connString // Postgres URLs can use a host query param to specify the host. This is // used for unix domain sockets (postgres:///dbname?host=/var/lib/postgres). if host := u.Query().Get("host"); u.Host == "" && host != "" { h.Host = host } return h, nil }
// ParseDSN creates a DSN (data source name) string by parsing the host. // It validates the resulting DSN and returns an error if the DSN is invalid. // // Format: [username[:password]@][protocol[(address)]]/ // Example: root:test@tcp(127.0.0.1:3306)/ func ParseDSN(mod mb.Module, host string) (mb.HostData, error) { c := struct { Username string `config:"username"` Password string `config:"password"` }{} if err := mod.UnpackConfig(&c); err != nil { return mb.HostData{}, err } config, err := mysql.ParseDSN(host) if err != nil { return mb.HostData{}, errors.Wrapf(err, "error parsing mysql host") } if config.User == "" { config.User = c.Username } if config.Passwd == "" { config.Passwd = c.Password } // Add connection timeouts to the DSN. if timeout := mod.Config().Timeout; timeout > 0 { config.Timeout = timeout config.ReadTimeout = timeout config.WriteTimeout = timeout } noCredentialsConfig := *config noCredentialsConfig.User = "" noCredentialsConfig.Passwd = "" return mb.HostData{ URI: config.FormatDSN(), SanitizedURI: noCredentialsConfig.FormatDSN(), Host: config.Addr, User: config.User, Password: config.Passwd, }, nil }