Source File
config.go
Belonging Package
github.com/jackc/pgconn
package pgconn
import (
)
type AfterConnectFunc func(ctx context.Context, pgconn *PgConn) error
type ValidateConnectFunc func(ctx context.Context, pgconn *PgConn) error
type Config struct {
Host string // host (e.g. localhost) or absolute path to unix domain socket directory (e.g. /private/tmp)
Port uint16
Database string
User string
Password string
TLSConfig *tls.Config // nil disables TLS
ConnectTimeout time.Duration
DialFunc DialFunc // e.g. net.Dialer.DialContext
LookupFunc LookupFunc // e.g. net.Resolver.LookupHost
BuildFrontend BuildFrontendFunc
RuntimeParams map[string]string // Run-time parameters to set on connection as session default values (e.g. search_path or application_name)
Fallbacks []*FallbackConfig
OnNotification NotificationHandler
createdByParseConfig bool // Used to enforce created by ParseConfig rule.
}
func ( *Config) () *Config {
:= new(Config)
* = *
if .TLSConfig != nil {
.TLSConfig = .TLSConfig.Clone()
}
if .RuntimeParams != nil {
.RuntimeParams = make(map[string]string, len(.RuntimeParams))
for , := range .RuntimeParams {
.RuntimeParams[] =
}
}
if .Fallbacks != nil {
.Fallbacks = make([]*FallbackConfig, len(.Fallbacks))
for , := range .Fallbacks {
:= new(FallbackConfig)
* = *
if .TLSConfig != nil {
.TLSConfig = .TLSConfig.Clone()
}
.Fallbacks[] =
}
}
return
}
func ( string) (*Config, error) {
:= defaultSettings()
:= parseEnvSettings()
:= make(map[string]string)
if != "" {
if strings.HasPrefix(, "postgres://") || strings.HasPrefix(, "postgresql://") {
, = parseURLSettings()
if != nil {
return nil, &parseConfigError{connString: , msg: "failed to parse as URL", err: }
}
} else {
, = parseDSNSettings()
if != nil {
return nil, &parseConfigError{connString: , msg: "failed to parse as DSN", err: }
}
}
}
:= mergeSettings(, , )
if , := ["service"]; {
, := parseServiceSettings(["servicefile"], )
if != nil {
return nil, &parseConfigError{connString: , msg: "failed to read service", err: }
}
= mergeSettings(, , , )
}
, := strconv.ParseInt(["min_read_buffer_size"], 10, 32)
if != nil {
return nil, &parseConfigError{connString: , msg: "cannot parse min_read_buffer_size", err: }
}
:= &Config{
createdByParseConfig: true,
Database: ["database"],
User: ["user"],
Password: ["password"],
RuntimeParams: make(map[string]string),
BuildFrontend: makeDefaultBuildFrontendFunc(int()),
}
if , := ["connect_timeout"]; {
, := parseConnectTimeoutSetting()
if != nil {
return nil, &parseConfigError{connString: , msg: "invalid connect_timeout", err: }
}
.ConnectTimeout =
.DialFunc = makeConnectTimeoutDialFunc()
} else {
:= makeDefaultDialer()
.DialFunc = .DialContext
}
.LookupFunc = makeDefaultResolver().LookupHost
:= map[string]struct{}{
"host": struct{}{},
"port": struct{}{},
"database": struct{}{},
"user": struct{}{},
"password": struct{}{},
"passfile": struct{}{},
"connect_timeout": struct{}{},
"sslmode": struct{}{},
"sslkey": struct{}{},
"sslcert": struct{}{},
"sslrootcert": struct{}{},
"target_session_attrs": struct{}{},
"min_read_buffer_size": struct{}{},
"service": struct{}{},
"servicefile": struct{}{},
}
for , := range {
if , := []; {
continue
}
.RuntimeParams[] =
}
:= []*FallbackConfig{}
:= strings.Split(["host"], ",")
:= strings.Split(["port"], ",")
for , := range {
var string
if < len() {
= []
} else {
= [0]
}
, := parsePort()
if != nil {
return nil, &parseConfigError{connString: , msg: "invalid port", err: }
}
var []*tls.Config
if , := NetworkAddress(, ); == "unix" {
= append(, nil)
} else {
var error
, = configTLS()
if != nil {
return nil, &parseConfigError{connString: , msg: "failed to configure TLS", err: }
}
}
for , := range {
= append(, &FallbackConfig{
Host: ,
Port: ,
TLSConfig: ,
})
}
}
.Host = [0].Host
.Port = [0].Port
.TLSConfig = [0].TLSConfig
.Fallbacks = [1:]
, := pgpassfile.ReadPassfile(["passfile"])
if == nil {
if .Password == "" {
:= .Host
if , := NetworkAddress(.Host, .Port); == "unix" {
= "localhost"
}
.Password = .FindPassword(, strconv.Itoa(int(.Port)), .Database, .User)
}
}
if ["target_session_attrs"] == "read-write" {
.ValidateConnect = ValidateConnectTargetSessionAttrsReadWrite
} else if ["target_session_attrs"] != "any" {
return nil, &parseConfigError{connString: , msg: fmt.Sprintf("unknown target_session_attrs value: %v", ["target_session_attrs"])}
}
return , nil
}
func ( ...map[string]string) map[string]string {
:= make(map[string]string)
for , := range {
for , := range {
[] =
}
}
return
}
func () map[string]string {
:= make(map[string]string)
:= map[string]string{
"PGHOST": "host",
"PGPORT": "port",
"PGDATABASE": "database",
"PGUSER": "user",
"PGPASSWORD": "password",
"PGPASSFILE": "passfile",
"PGAPPNAME": "application_name",
"PGCONNECT_TIMEOUT": "connect_timeout",
"PGSSLMODE": "sslmode",
"PGSSLKEY": "sslkey",
"PGSSLCERT": "sslcert",
"PGSSLROOTCERT": "sslrootcert",
"PGTARGETSESSIONATTRS": "target_session_attrs",
"PGSERVICE": "service",
"PGSERVICEFILE": "servicefile",
}
for , := range {
:= os.Getenv()
if != "" {
[] =
}
}
return
}
func ( string) (map[string]string, error) {
:= make(map[string]string)
, := url.Parse()
if != nil {
return nil,
}
if .User != nil {
["user"] = .User.Username()
if , := .User.Password(); {
["password"] =
}
}
var []string
var []string
for , := range strings.Split(.Host, ",") {
if == "" {
continue
}
if isIPOnly() {
= append(, strings.Trim(, "[]"))
continue
}
, , := net.SplitHostPort()
if != nil {
return nil, fmt.Errorf("failed to split host:port in '%s', err: %w", , )
}
= append(, )
= append(, )
}
if len() > 0 {
["host"] = strings.Join(, ",")
}
if len() > 0 {
["port"] = strings.Join(, ",")
}
:= strings.TrimLeft(.Path, "/")
if != "" {
["database"] =
}
for , := range .Query() {
[] = [0]
}
return , nil
}
func ( string) bool {
return net.ParseIP(strings.Trim(, "[]")) != nil || !strings.Contains(, ":")
}
var asciiSpace = [256]uint8{'\t': 1, '\n': 1, '\v': 1, '\f': 1, '\r': 1, ' ': 1}
func ( string) (map[string]string, error) {
:= make(map[string]string)
:= map[string]string{
"dbname": "database",
}
for len() > 0 {
var , string
:= strings.IndexRune(, '=')
if < 0 {
return nil, errors.New("invalid dsn")
}
= strings.Trim([:], " \t\n\r\v\f")
= strings.TrimLeft([+1:], " \t\n\r\v\f")
if len() == 0 {
} else if [0] != '\'' {
:= 0
for ; < len(); ++ {
if asciiSpace[[]] == 1 {
break
}
if [] == '\\' {
++
if == len() {
return nil, errors.New("invalid backslash")
}
}
}
= strings.Replace(strings.Replace([:], "\\\\", "\\", -1), "\\'", "'", -1)
if == len() {
= ""
} else {
= [+1:]
}
} else { // quoted string
= [1:]
:= 0
for ; < len(); ++ {
if [] == '\'' {
break
}
if [] == '\\' {
++
}
}
if == len() {
return nil, errors.New("unterminated quoted string in connection info string")
}
= strings.Replace(strings.Replace([:], "\\\\", "\\", -1), "\\'", "'", -1)
if == len() {
= ""
} else {
= [+1:]
}
}
if , := []; {
=
}
if == "" {
return nil, errors.New("invalid dsn")
}
[] =
}
return , nil
}
func (, string) (map[string]string, error) {
, := pgservicefile.ReadServicefile()
if != nil {
return nil, fmt.Errorf("failed to read service file: %v", )
}
, := .GetService()
if != nil {
return nil, fmt.Errorf("unable to find service: %v", )
}
:= map[string]string{
"dbname": "database",
}
:= make(map[string]string, len(.Settings))
for , := range .Settings {
if , := []; {
=
}
[] =
}
return , nil
}
if != "" {
goto
}
.InsecureSkipVerify = true
break
:
fallthrough
.InsecureSkipVerify = true
.VerifyPeerCertificate = func( [][]byte, [][]*x509.Certificate) error {
:= make([]*x509.Certificate, len())
for , := range {
, := x509.ParseCertificate()
if != nil {
return errors.New("failed to parse certificate from server: " + .Error())
}
[] =
}
:= x509.VerifyOptions{
Roots: .RootCAs,
Intermediates: x509.NewCertPool(),
for , := range [1:] {
.Intermediates.AddCert()
}
, := [0].Verify()
return
}
case "verify-full":
.ServerName =
default:
return nil, errors.New("sslmode is invalid")
}
if != "" {
:= x509.NewCertPool()
:=
, := ioutil.ReadFile()
if != nil {
return nil, fmt.Errorf("unable to read CA file: %w", )
}
if !.AppendCertsFromPEM() {
return nil, errors.New("unable to add CA to cert pool")
}
.RootCAs =
.ClientCAs =
}
if ( != "" && == "") || ( == "" && != "") {
return nil, errors.New(`both "sslcert" and "sslkey" are required`)
}
if != "" && != "" {
, := tls.LoadX509KeyPair(, )
if != nil {
return nil, fmt.Errorf("unable to read cert: %w", )
}
.Certificates = []tls.Certificate{}
}
switch {
case "allow":
return []*tls.Config{nil, }, nil
case "prefer":
return []*tls.Config{, nil}, nil
case "require", "verify-ca", "verify-full":
return []*tls.Config{}, nil
default:
panic("BUG: bad sslmode should already have been caught")
}
}
func ( string) (uint16, error) {
, := strconv.ParseUint(, 10, 16)
if != nil {
return 0,
}
if < 1 || > math.MaxUint16 {
return 0, errors.New("outside range")
}
return uint16(), nil
}
func () *net.Dialer {
return &net.Dialer{KeepAlive: 5 * time.Minute}
}
func () *net.Resolver {
return net.DefaultResolver
}
func ( int) BuildFrontendFunc {
return func( io.Reader, io.Writer) Frontend {
, := chunkreader.NewConfig(, chunkreader.Config{MinBufLen: })
if != nil {
panic(fmt.Sprintf("BUG: chunkreader.NewConfig failed: %v", ))
}
:= pgproto3.NewFrontend(, )
return
}
}
func ( string) (time.Duration, error) {
, := strconv.ParseInt(, 10, 64)
if != nil {
return 0,
}
if < 0 {
return 0, errors.New("negative timeout")
}
return time.Duration() * time.Second, nil
}
func ( time.Duration) DialFunc {
:= makeDefaultDialer()
.Timeout =
return .DialContext
}
![]() |
The pages are generated with Golds v0.3.2-preview. (GOOS=darwin GOARCH=amd64) Golds is a Go 101 project developed by Tapir Liu. PR and bug reports are welcome and can be submitted to the issue list. Please follow @Go100and1 (reachable from the left QR code) to get the latest news of Golds. |