Updating server dependancies (#5249)
Этот коммит содержится в:
коммит произвёл
Harrison Healey
родитель
ca3211bc04
Коммит
701d1ab638
14
vendor/github.com/lib/pq/.travis.yml
сгенерированный
поставляемый
14
vendor/github.com/lib/pq/.travis.yml
сгенерированный
поставляемый
@@ -1,10 +1,11 @@
|
||||
language: go
|
||||
|
||||
go:
|
||||
- 1.5
|
||||
- 1.6
|
||||
- 1.7
|
||||
- tip
|
||||
- 1.5.x
|
||||
- 1.6.x
|
||||
- 1.7.x
|
||||
- 1.8.x
|
||||
- master
|
||||
|
||||
sudo: true
|
||||
|
||||
@@ -15,6 +16,7 @@ env:
|
||||
- PQSSLCERTTEST_PATH=$PWD/certs
|
||||
- PGHOST=127.0.0.1
|
||||
matrix:
|
||||
- PGVERSION=9.6
|
||||
- PGVERSION=9.5
|
||||
- PGVERSION=9.4
|
||||
- PGVERSION=9.3
|
||||
@@ -39,5 +41,5 @@ script:
|
||||
- >
|
||||
goimports -d -e $(find -name '*.go') | awk '{ print } END { exit NR == 0 ? 0 : 1 }'
|
||||
- go vet ./...
|
||||
- PQTEST_BINARY_PARAMETERS=no go test -v ./...
|
||||
- PQTEST_BINARY_PARAMETERS=yes go test -v ./...
|
||||
- PQTEST_BINARY_PARAMETERS=no go test -race -v ./...
|
||||
- PQTEST_BINARY_PARAMETERS=yes go test -race -v ./...
|
||||
|
||||
45
vendor/github.com/lib/pq/array.go
сгенерированный
поставляемый
45
vendor/github.com/lib/pq/array.go
сгенерированный
поставляемый
@@ -70,6 +70,9 @@ func (a *BoolArray) Scan(src interface{}) error {
|
||||
return a.scanBytes(src)
|
||||
case string:
|
||||
return a.scanBytes([]byte(src))
|
||||
case nil:
|
||||
*a = nil
|
||||
return nil
|
||||
}
|
||||
|
||||
return fmt.Errorf("pq: cannot convert %T to BoolArray", src)
|
||||
@@ -80,7 +83,7 @@ func (a *BoolArray) scanBytes(src []byte) error {
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if len(elems) == 0 {
|
||||
if *a != nil && len(elems) == 0 {
|
||||
*a = (*a)[:0]
|
||||
} else {
|
||||
b := make(BoolArray, len(elems))
|
||||
@@ -141,6 +144,9 @@ func (a *ByteaArray) Scan(src interface{}) error {
|
||||
return a.scanBytes(src)
|
||||
case string:
|
||||
return a.scanBytes([]byte(src))
|
||||
case nil:
|
||||
*a = nil
|
||||
return nil
|
||||
}
|
||||
|
||||
return fmt.Errorf("pq: cannot convert %T to ByteaArray", src)
|
||||
@@ -151,7 +157,7 @@ func (a *ByteaArray) scanBytes(src []byte) error {
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if len(elems) == 0 {
|
||||
if *a != nil && len(elems) == 0 {
|
||||
*a = (*a)[:0]
|
||||
} else {
|
||||
b := make(ByteaArray, len(elems))
|
||||
@@ -210,6 +216,9 @@ func (a *Float64Array) Scan(src interface{}) error {
|
||||
return a.scanBytes(src)
|
||||
case string:
|
||||
return a.scanBytes([]byte(src))
|
||||
case nil:
|
||||
*a = nil
|
||||
return nil
|
||||
}
|
||||
|
||||
return fmt.Errorf("pq: cannot convert %T to Float64Array", src)
|
||||
@@ -220,7 +229,7 @@ func (a *Float64Array) scanBytes(src []byte) error {
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if len(elems) == 0 {
|
||||
if *a != nil && len(elems) == 0 {
|
||||
*a = (*a)[:0]
|
||||
} else {
|
||||
b := make(Float64Array, len(elems))
|
||||
@@ -320,6 +329,11 @@ func (a GenericArray) Scan(src interface{}) error {
|
||||
return a.scanBytes(src, dv)
|
||||
case string:
|
||||
return a.scanBytes([]byte(src), dv)
|
||||
case nil:
|
||||
if dv.Kind() == reflect.Slice {
|
||||
dv.Set(reflect.Zero(dv.Type()))
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
return fmt.Errorf("pq: cannot convert %T to %s", src, dv.Type())
|
||||
@@ -386,7 +400,13 @@ func (a GenericArray) Value() (driver.Value, error) {
|
||||
|
||||
rv := reflect.ValueOf(a.A)
|
||||
|
||||
if k := rv.Kind(); k != reflect.Array && k != reflect.Slice {
|
||||
switch rv.Kind() {
|
||||
case reflect.Slice:
|
||||
if rv.IsNil() {
|
||||
return nil, nil
|
||||
}
|
||||
case reflect.Array:
|
||||
default:
|
||||
return nil, fmt.Errorf("pq: Unable to convert %T to array", a.A)
|
||||
}
|
||||
|
||||
@@ -412,6 +432,9 @@ func (a *Int64Array) Scan(src interface{}) error {
|
||||
return a.scanBytes(src)
|
||||
case string:
|
||||
return a.scanBytes([]byte(src))
|
||||
case nil:
|
||||
*a = nil
|
||||
return nil
|
||||
}
|
||||
|
||||
return fmt.Errorf("pq: cannot convert %T to Int64Array", src)
|
||||
@@ -422,7 +445,7 @@ func (a *Int64Array) scanBytes(src []byte) error {
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if len(elems) == 0 {
|
||||
if *a != nil && len(elems) == 0 {
|
||||
*a = (*a)[:0]
|
||||
} else {
|
||||
b := make(Int64Array, len(elems))
|
||||
@@ -470,6 +493,9 @@ func (a *StringArray) Scan(src interface{}) error {
|
||||
return a.scanBytes(src)
|
||||
case string:
|
||||
return a.scanBytes([]byte(src))
|
||||
case nil:
|
||||
*a = nil
|
||||
return nil
|
||||
}
|
||||
|
||||
return fmt.Errorf("pq: cannot convert %T to StringArray", src)
|
||||
@@ -480,7 +506,7 @@ func (a *StringArray) scanBytes(src []byte) error {
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if len(elems) == 0 {
|
||||
if *a != nil && len(elems) == 0 {
|
||||
*a = (*a)[:0]
|
||||
} else {
|
||||
b := make(StringArray, len(elems))
|
||||
@@ -639,6 +665,9 @@ Element:
|
||||
for i < len(src) {
|
||||
switch src[i] {
|
||||
case '{':
|
||||
if depth == len(dims) {
|
||||
break Element
|
||||
}
|
||||
depth++
|
||||
dims[depth-1] = 0
|
||||
i++
|
||||
@@ -680,11 +709,11 @@ Element:
|
||||
}
|
||||
|
||||
for i < len(src) {
|
||||
if bytes.HasPrefix(src[i:], del) {
|
||||
if bytes.HasPrefix(src[i:], del) && depth > 0 {
|
||||
dims[depth-1]++
|
||||
i += len(del)
|
||||
goto Element
|
||||
} else if src[i] == '}' {
|
||||
} else if src[i] == '}' && depth > 0 {
|
||||
dims[depth-1]++
|
||||
depth--
|
||||
i++
|
||||
|
||||
164
vendor/github.com/lib/pq/array_test.go
сгенерированный
поставляемый
164
vendor/github.com/lib/pq/array_test.go
сгенерированный
поставляемый
@@ -70,6 +70,10 @@ func TestParseArrayError(t *testing.T) {
|
||||
{`{,}`, "unexpected ',' at offset 1"},
|
||||
{`{,x}`, "unexpected ',' at offset 1"},
|
||||
{`{x,}`, "unexpected '}' at offset 3"},
|
||||
{`{x,{`, "unexpected '{' at offset 3"},
|
||||
{`{x},`, "unexpected ',' at offset 3"},
|
||||
{`{x}}`, "unexpected '}' at offset 3"},
|
||||
{`{{x}`, "expected '}' at offset 4"},
|
||||
{`{""x}`, "unexpected 'x' at offset 3"},
|
||||
{`{{a},{b,c}}`, "multidimensional arrays must have elements with matching dimensions"},
|
||||
} {
|
||||
@@ -171,6 +175,30 @@ func TestBoolArrayScanUnsupported(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestBoolArrayScanEmpty(t *testing.T) {
|
||||
var arr BoolArray
|
||||
err := arr.Scan(`{}`)
|
||||
|
||||
if err != nil {
|
||||
t.Fatalf("Expected no error, got %v", err)
|
||||
}
|
||||
if arr == nil || len(arr) != 0 {
|
||||
t.Errorf("Expected empty, got %#v", arr)
|
||||
}
|
||||
}
|
||||
|
||||
func TestBoolArrayScanNil(t *testing.T) {
|
||||
arr := BoolArray{true, true, true}
|
||||
err := arr.Scan(nil)
|
||||
|
||||
if err != nil {
|
||||
t.Fatalf("Expected no error, got %v", err)
|
||||
}
|
||||
if arr != nil {
|
||||
t.Errorf("Expected nil, got %+v", arr)
|
||||
}
|
||||
}
|
||||
|
||||
var BoolArrayStringTests = []struct {
|
||||
str string
|
||||
arr BoolArray
|
||||
@@ -300,6 +328,30 @@ func TestByteaArrayScanUnsupported(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestByteaArrayScanEmpty(t *testing.T) {
|
||||
var arr ByteaArray
|
||||
err := arr.Scan(`{}`)
|
||||
|
||||
if err != nil {
|
||||
t.Fatalf("Expected no error, got %v", err)
|
||||
}
|
||||
if arr == nil || len(arr) != 0 {
|
||||
t.Errorf("Expected empty, got %#v", arr)
|
||||
}
|
||||
}
|
||||
|
||||
func TestByteaArrayScanNil(t *testing.T) {
|
||||
arr := ByteaArray{{2}, {6}, {0, 0}}
|
||||
err := arr.Scan(nil)
|
||||
|
||||
if err != nil {
|
||||
t.Fatalf("Expected no error, got %v", err)
|
||||
}
|
||||
if arr != nil {
|
||||
t.Errorf("Expected nil, got %+v", arr)
|
||||
}
|
||||
}
|
||||
|
||||
var ByteaArrayStringTests = []struct {
|
||||
str string
|
||||
arr ByteaArray
|
||||
@@ -430,6 +482,30 @@ func TestFloat64ArrayScanUnsupported(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestFloat64ArrayScanEmpty(t *testing.T) {
|
||||
var arr Float64Array
|
||||
err := arr.Scan(`{}`)
|
||||
|
||||
if err != nil {
|
||||
t.Fatalf("Expected no error, got %v", err)
|
||||
}
|
||||
if arr == nil || len(arr) != 0 {
|
||||
t.Errorf("Expected empty, got %#v", arr)
|
||||
}
|
||||
}
|
||||
|
||||
func TestFloat64ArrayScanNil(t *testing.T) {
|
||||
arr := Float64Array{5, 5, 5}
|
||||
err := arr.Scan(nil)
|
||||
|
||||
if err != nil {
|
||||
t.Fatalf("Expected no error, got %v", err)
|
||||
}
|
||||
if arr != nil {
|
||||
t.Errorf("Expected nil, got %+v", arr)
|
||||
}
|
||||
}
|
||||
|
||||
var Float64ArrayStringTests = []struct {
|
||||
str string
|
||||
arr Float64Array
|
||||
@@ -560,6 +636,30 @@ func TestInt64ArrayScanUnsupported(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestInt64ArrayScanEmpty(t *testing.T) {
|
||||
var arr Int64Array
|
||||
err := arr.Scan(`{}`)
|
||||
|
||||
if err != nil {
|
||||
t.Fatalf("Expected no error, got %v", err)
|
||||
}
|
||||
if arr == nil || len(arr) != 0 {
|
||||
t.Errorf("Expected empty, got %#v", arr)
|
||||
}
|
||||
}
|
||||
|
||||
func TestInt64ArrayScanNil(t *testing.T) {
|
||||
arr := Int64Array{5, 5, 5}
|
||||
err := arr.Scan(nil)
|
||||
|
||||
if err != nil {
|
||||
t.Fatalf("Expected no error, got %v", err)
|
||||
}
|
||||
if arr != nil {
|
||||
t.Errorf("Expected nil, got %+v", arr)
|
||||
}
|
||||
}
|
||||
|
||||
var Int64ArrayStringTests = []struct {
|
||||
str string
|
||||
arr Int64Array
|
||||
@@ -689,6 +789,30 @@ func TestStringArrayScanUnsupported(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestStringArrayScanEmpty(t *testing.T) {
|
||||
var arr StringArray
|
||||
err := arr.Scan(`{}`)
|
||||
|
||||
if err != nil {
|
||||
t.Fatalf("Expected no error, got %v", err)
|
||||
}
|
||||
if arr == nil || len(arr) != 0 {
|
||||
t.Errorf("Expected empty, got %#v", arr)
|
||||
}
|
||||
}
|
||||
|
||||
func TestStringArrayScanNil(t *testing.T) {
|
||||
arr := StringArray{"x", "x", "x"}
|
||||
err := arr.Scan(nil)
|
||||
|
||||
if err != nil {
|
||||
t.Fatalf("Expected no error, got %v", err)
|
||||
}
|
||||
if arr != nil {
|
||||
t.Errorf("Expected nil, got %+v", arr)
|
||||
}
|
||||
}
|
||||
|
||||
var StringArrayStringTests = []struct {
|
||||
str string
|
||||
arr StringArray
|
||||
@@ -811,6 +935,7 @@ func BenchmarkStringArrayValue(b *testing.B) {
|
||||
func TestGenericArrayScanUnsupported(t *testing.T) {
|
||||
var s string
|
||||
var ss []string
|
||||
var nsa [1]sql.NullString
|
||||
|
||||
for _, tt := range []struct {
|
||||
src, dest interface{}
|
||||
@@ -820,6 +945,7 @@ func TestGenericArrayScanUnsupported(t *testing.T) {
|
||||
{nil, true, "destination bool is not a pointer to array or slice"},
|
||||
{nil, &s, "destination *string is not a pointer to array or slice"},
|
||||
{nil, ss, "destination []string is not a pointer to array or slice"},
|
||||
{nil, &nsa, "<nil> to [1]sql.NullString"},
|
||||
{true, &ss, "bool to []string"},
|
||||
{`{{x}}`, &ss, "multidimensional ARRAY[1][1] is not implemented"},
|
||||
{`{{x},{x}}`, &ss, "multidimensional ARRAY[2][1] is not implemented"},
|
||||
@@ -862,6 +988,28 @@ func TestGenericArrayScanScannerArrayString(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestGenericArrayScanScannerSliceEmpty(t *testing.T) {
|
||||
var nss []sql.NullString
|
||||
|
||||
if err := (GenericArray{&nss}).Scan(`{}`); err != nil {
|
||||
t.Fatalf("Expected no error, got %v", err)
|
||||
}
|
||||
if nss == nil || len(nss) != 0 {
|
||||
t.Errorf("Expected empty, got %#v", nss)
|
||||
}
|
||||
}
|
||||
|
||||
func TestGenericArrayScanScannerSliceNil(t *testing.T) {
|
||||
nss := []sql.NullString{{String: ``, Valid: true}, {}}
|
||||
|
||||
if err := (GenericArray{&nss}).Scan(nil); err != nil {
|
||||
t.Fatalf("Expected no error, got %v", err)
|
||||
}
|
||||
if nss != nil {
|
||||
t.Errorf("Expected nil, got %+v", nss)
|
||||
}
|
||||
}
|
||||
|
||||
func TestGenericArrayScanScannerSliceBytes(t *testing.T) {
|
||||
src, expected, nss := []byte(`{NULL,abc,"\""}`),
|
||||
[]sql.NullString{{}, {String: `abc`, Valid: true}, {String: `"`, Valid: true}},
|
||||
@@ -977,6 +1125,22 @@ func TestGenericArrayValue(t *testing.T) {
|
||||
t.Errorf("Expected nil, got %q", result)
|
||||
}
|
||||
|
||||
for _, tt := range []interface{}{
|
||||
[]bool(nil),
|
||||
[][]int(nil),
|
||||
[]*int(nil),
|
||||
[]sql.NullString(nil),
|
||||
} {
|
||||
result, err := GenericArray{tt}.Value()
|
||||
|
||||
if err != nil {
|
||||
t.Fatalf("Expected no error for %#v, got %v", tt, err)
|
||||
}
|
||||
if result != nil {
|
||||
t.Errorf("Expected nil for %#v, got %q", tt, result)
|
||||
}
|
||||
}
|
||||
|
||||
Tilde := func(v driver.Value) FuncArrayValuer {
|
||||
return FuncArrayValuer{
|
||||
func() string { return "~" },
|
||||
|
||||
189
vendor/github.com/lib/pq/conn.go
сгенерированный
поставляемый
189
vendor/github.com/lib/pq/conn.go
сгенерированный
поставляемый
@@ -3,15 +3,12 @@ package pq
|
||||
import (
|
||||
"bufio"
|
||||
"crypto/md5"
|
||||
"crypto/tls"
|
||||
"crypto/x509"
|
||||
"database/sql"
|
||||
"database/sql/driver"
|
||||
"encoding/binary"
|
||||
"errors"
|
||||
"fmt"
|
||||
"io"
|
||||
"io/ioutil"
|
||||
"net"
|
||||
"os"
|
||||
"os/user"
|
||||
@@ -101,6 +98,15 @@ type conn struct {
|
||||
namei int
|
||||
scratch [512]byte
|
||||
txnStatus transactionStatus
|
||||
txnClosed chan<- struct{}
|
||||
|
||||
// Save connection arguments to use during CancelRequest.
|
||||
dialer Dialer
|
||||
opts values
|
||||
|
||||
// Cancellation key data for use with CancelRequest messages.
|
||||
processID int
|
||||
secretKey int
|
||||
|
||||
parameterStatus parameterStatus
|
||||
|
||||
@@ -310,7 +316,10 @@ func DialOpen(d Dialer, name string) (_ driver.Conn, err error) {
|
||||
}
|
||||
}
|
||||
|
||||
cn := &conn{}
|
||||
cn := &conn{
|
||||
opts: o,
|
||||
dialer: d,
|
||||
}
|
||||
err = cn.handleDriverSettings(o)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
@@ -532,7 +541,15 @@ func (cn *conn) Begin() (_ driver.Tx, err error) {
|
||||
return cn, nil
|
||||
}
|
||||
|
||||
func (cn *conn) closeTxn() {
|
||||
if cn.txnClosed != nil {
|
||||
close(cn.txnClosed)
|
||||
cn.txnClosed = nil
|
||||
}
|
||||
}
|
||||
|
||||
func (cn *conn) Commit() (err error) {
|
||||
defer cn.closeTxn()
|
||||
if cn.bad {
|
||||
return driver.ErrBadConn
|
||||
}
|
||||
@@ -568,6 +585,7 @@ func (cn *conn) Commit() (err error) {
|
||||
}
|
||||
|
||||
func (cn *conn) Rollback() (err error) {
|
||||
defer cn.closeTxn()
|
||||
if cn.bad {
|
||||
return driver.ErrBadConn
|
||||
}
|
||||
@@ -718,6 +736,8 @@ func decideColumnFormats(colTyps []oid.Oid, forceText bool) (colFmts []format, c
|
||||
case oid.T_int4:
|
||||
fallthrough
|
||||
case oid.T_int2:
|
||||
fallthrough
|
||||
case oid.T_uuid:
|
||||
colFmts[i] = formatBinary
|
||||
allText = false
|
||||
|
||||
@@ -797,7 +817,11 @@ func (cn *conn) Close() (err error) {
|
||||
}
|
||||
|
||||
// Implement the "Queryer" interface
|
||||
func (cn *conn) Query(query string, args []driver.Value) (_ driver.Rows, err error) {
|
||||
func (cn *conn) Query(query string, args []driver.Value) (driver.Rows, error) {
|
||||
return cn.query(query, args)
|
||||
}
|
||||
|
||||
func (cn *conn) query(query string, args []driver.Value) (_ *rows, err error) {
|
||||
if cn.bad {
|
||||
return nil, driver.ErrBadConn
|
||||
}
|
||||
@@ -1000,42 +1024,12 @@ func (cn *conn) recv1() (t byte, r *readBuf) {
|
||||
}
|
||||
|
||||
func (cn *conn) ssl(o values) {
|
||||
verifyCaOnly := false
|
||||
tlsConf := tls.Config{}
|
||||
switch mode := o.Get("sslmode"); mode {
|
||||
// "require" is the default.
|
||||
case "", "require":
|
||||
// We must skip TLS's own verification since it requires full
|
||||
// verification since Go 1.3.
|
||||
tlsConf.InsecureSkipVerify = true
|
||||
|
||||
// From http://www.postgresql.org/docs/current/static/libpq-ssl.html:
|
||||
// Note: For backwards compatibility with earlier versions of PostgreSQL, if a
|
||||
// root CA file exists, the behavior of sslmode=require will be the same as
|
||||
// that of verify-ca, meaning the server certificate is validated against the
|
||||
// CA. Relying on this behavior is discouraged, and applications that need
|
||||
// certificate validation should always use verify-ca or verify-full.
|
||||
if _, err := os.Stat(o.Get("sslrootcert")); err == nil {
|
||||
verifyCaOnly = true
|
||||
} else {
|
||||
o.Set("sslrootcert", "")
|
||||
}
|
||||
case "verify-ca":
|
||||
// We must skip TLS's own verification since it requires full
|
||||
// verification since Go 1.3.
|
||||
tlsConf.InsecureSkipVerify = true
|
||||
verifyCaOnly = true
|
||||
case "verify-full":
|
||||
tlsConf.ServerName = o.Get("host")
|
||||
case "disable":
|
||||
upgrade := ssl(o)
|
||||
if upgrade == nil {
|
||||
// Nothing to do
|
||||
return
|
||||
default:
|
||||
errorf(`unsupported sslmode %q; only "require" (default), "verify-full", "verify-ca", and "disable" supported`, mode)
|
||||
}
|
||||
|
||||
cn.setupSSLClientCertificates(&tlsConf, o)
|
||||
cn.setupSSLCA(&tlsConf, o)
|
||||
|
||||
w := cn.writeBuf(0)
|
||||
w.int32(80877103)
|
||||
cn.sendStartupPacket(w)
|
||||
@@ -1050,114 +1044,7 @@ func (cn *conn) ssl(o values) {
|
||||
panic(ErrSSLNotSupported)
|
||||
}
|
||||
|
||||
client := tls.Client(cn.c, &tlsConf)
|
||||
if verifyCaOnly {
|
||||
cn.verifyCA(client, &tlsConf)
|
||||
}
|
||||
cn.c = client
|
||||
}
|
||||
|
||||
// verifyCA carries out a TLS handshake to the server and verifies the
|
||||
// presented certificate against the effective CA, i.e. the one specified in
|
||||
// sslrootcert or the system CA if sslrootcert was not specified.
|
||||
func (cn *conn) verifyCA(client *tls.Conn, tlsConf *tls.Config) {
|
||||
err := client.Handshake()
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
certs := client.ConnectionState().PeerCertificates
|
||||
opts := x509.VerifyOptions{
|
||||
DNSName: client.ConnectionState().ServerName,
|
||||
Intermediates: x509.NewCertPool(),
|
||||
Roots: tlsConf.RootCAs,
|
||||
}
|
||||
for i, cert := range certs {
|
||||
if i == 0 {
|
||||
continue
|
||||
}
|
||||
opts.Intermediates.AddCert(cert)
|
||||
}
|
||||
_, err = certs[0].Verify(opts)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
}
|
||||
|
||||
// This function sets up SSL client certificates based on either the "sslkey"
|
||||
// and "sslcert" settings (possibly set via the environment variables PGSSLKEY
|
||||
// and PGSSLCERT, respectively), or if they aren't set, from the .postgresql
|
||||
// directory in the user's home directory. If the file paths are set
|
||||
// explicitly, the files must exist. The key file must also not be
|
||||
// world-readable, or this function will panic with
|
||||
// ErrSSLKeyHasWorldPermissions.
|
||||
func (cn *conn) setupSSLClientCertificates(tlsConf *tls.Config, o values) {
|
||||
var missingOk bool
|
||||
|
||||
sslkey := o.Get("sslkey")
|
||||
sslcert := o.Get("sslcert")
|
||||
if sslkey != "" && sslcert != "" {
|
||||
// If the user has set an sslkey and sslcert, they *must* exist.
|
||||
missingOk = false
|
||||
} else {
|
||||
// Automatically load certificates from ~/.postgresql.
|
||||
user, err := user.Current()
|
||||
if err != nil {
|
||||
// user.Current() might fail when cross-compiling. We have to
|
||||
// ignore the error and continue without client certificates, since
|
||||
// we wouldn't know where to load them from.
|
||||
return
|
||||
}
|
||||
|
||||
sslkey = filepath.Join(user.HomeDir, ".postgresql", "postgresql.key")
|
||||
sslcert = filepath.Join(user.HomeDir, ".postgresql", "postgresql.crt")
|
||||
missingOk = true
|
||||
}
|
||||
|
||||
// Check that both files exist, and report the error or stop, depending on
|
||||
// which behaviour we want. Note that we don't do any more extensive
|
||||
// checks than this (such as checking that the paths aren't directories);
|
||||
// LoadX509KeyPair() will take care of the rest.
|
||||
keyfinfo, err := os.Stat(sslkey)
|
||||
if err != nil && missingOk {
|
||||
return
|
||||
} else if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
_, err = os.Stat(sslcert)
|
||||
if err != nil && missingOk {
|
||||
return
|
||||
} else if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
// If we got this far, the key file must also have the correct permissions
|
||||
kmode := keyfinfo.Mode()
|
||||
if kmode != kmode&0600 {
|
||||
panic(ErrSSLKeyHasWorldPermissions)
|
||||
}
|
||||
|
||||
cert, err := tls.LoadX509KeyPair(sslcert, sslkey)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
tlsConf.Certificates = []tls.Certificate{cert}
|
||||
}
|
||||
|
||||
// Sets up RootCAs in the TLS configuration if sslrootcert is set.
|
||||
func (cn *conn) setupSSLCA(tlsConf *tls.Config, o values) {
|
||||
if sslrootcert := o.Get("sslrootcert"); sslrootcert != "" {
|
||||
tlsConf.RootCAs = x509.NewCertPool()
|
||||
|
||||
cert, err := ioutil.ReadFile(sslrootcert)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
ok := tlsConf.RootCAs.AppendCertsFromPEM(cert)
|
||||
if !ok {
|
||||
errorf("couldn't parse pem in sslrootcert")
|
||||
}
|
||||
}
|
||||
cn.c = upgrade(cn.c)
|
||||
}
|
||||
|
||||
// isDriverSetting returns true iff a setting is purely for configuring the
|
||||
@@ -1212,6 +1099,7 @@ func (cn *conn) startup(o values) {
|
||||
t, r := cn.recv()
|
||||
switch t {
|
||||
case 'K':
|
||||
cn.processBackendKeyData(r)
|
||||
case 'S':
|
||||
cn.processParameterStatus(r)
|
||||
case 'R':
|
||||
@@ -1439,6 +1327,7 @@ func (cn *conn) parseComplete(commandTag string) (driver.Result, string) {
|
||||
|
||||
type rows struct {
|
||||
cn *conn
|
||||
closed chan<- struct{}
|
||||
colNames []string
|
||||
colTyps []oid.Oid
|
||||
colFmts []format
|
||||
@@ -1447,6 +1336,9 @@ type rows struct {
|
||||
}
|
||||
|
||||
func (rs *rows) Close() error {
|
||||
if rs.closed != nil {
|
||||
defer close(rs.closed)
|
||||
}
|
||||
// no need to look at cn.bad as Next() will
|
||||
for {
|
||||
err := rs.Next(nil)
|
||||
@@ -1651,6 +1543,11 @@ func (cn *conn) readReadyForQuery() {
|
||||
}
|
||||
}
|
||||
|
||||
func (c *conn) processBackendKeyData(r *readBuf) {
|
||||
c.processID = r.int32()
|
||||
c.secretKey = r.int32()
|
||||
}
|
||||
|
||||
func (cn *conn) readParseResponse() {
|
||||
t, r := cn.recv1()
|
||||
switch t {
|
||||
|
||||
92
vendor/github.com/lib/pq/conn_go18.go
сгенерированный
поставляемый
Обычный файл
92
vendor/github.com/lib/pq/conn_go18.go
сгенерированный
поставляемый
Обычный файл
@@ -0,0 +1,92 @@
|
||||
// +build go1.8
|
||||
|
||||
package pq
|
||||
|
||||
import (
|
||||
"context"
|
||||
"database/sql/driver"
|
||||
"errors"
|
||||
)
|
||||
|
||||
// Implement the "QueryerContext" interface
|
||||
func (cn *conn) QueryContext(ctx context.Context, query string, args []driver.NamedValue) (driver.Rows, error) {
|
||||
list := make([]driver.Value, len(args))
|
||||
for i, nv := range args {
|
||||
list[i] = nv.Value
|
||||
}
|
||||
var closed chan<- struct{}
|
||||
if ctx.Done() != nil {
|
||||
closed = watchCancel(ctx, cn.cancel)
|
||||
}
|
||||
r, err := cn.query(query, list)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
r.closed = closed
|
||||
return r, nil
|
||||
}
|
||||
|
||||
// Implement the "ExecerContext" interface
|
||||
func (cn *conn) ExecContext(ctx context.Context, query string, args []driver.NamedValue) (driver.Result, error) {
|
||||
list := make([]driver.Value, len(args))
|
||||
for i, nv := range args {
|
||||
list[i] = nv.Value
|
||||
}
|
||||
|
||||
if ctx.Done() != nil {
|
||||
closed := watchCancel(ctx, cn.cancel)
|
||||
defer close(closed)
|
||||
}
|
||||
|
||||
return cn.Exec(query, list)
|
||||
}
|
||||
|
||||
// Implement the "ConnBeginTx" interface
|
||||
func (cn *conn) BeginTx(ctx context.Context, opts driver.TxOptions) (driver.Tx, error) {
|
||||
if opts.Isolation != 0 {
|
||||
return nil, errors.New("isolation levels not supported")
|
||||
}
|
||||
if opts.ReadOnly {
|
||||
return nil, errors.New("read-only transactions not supported")
|
||||
}
|
||||
tx, err := cn.Begin()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if ctx.Done() != nil {
|
||||
cn.txnClosed = watchCancel(ctx, cn.cancel)
|
||||
}
|
||||
return tx, nil
|
||||
}
|
||||
|
||||
func watchCancel(ctx context.Context, cancel func()) chan<- struct{} {
|
||||
closed := make(chan struct{})
|
||||
go func() {
|
||||
select {
|
||||
case <-ctx.Done():
|
||||
cancel()
|
||||
case <-closed:
|
||||
}
|
||||
}()
|
||||
return closed
|
||||
}
|
||||
|
||||
func (cn *conn) cancel() {
|
||||
var err error
|
||||
can := &conn{}
|
||||
can.c, err = dial(cn.dialer, cn.opts)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
can.ssl(cn.opts)
|
||||
|
||||
defer can.errRecover(&err)
|
||||
|
||||
w := can.writeBuf(0)
|
||||
w.int32(80877102) // cancel request code
|
||||
w.int32(cn.processID)
|
||||
w.int32(cn.secretKey)
|
||||
|
||||
can.sendStartupPacket(w)
|
||||
_ = can.c.Close()
|
||||
}
|
||||
27
vendor/github.com/lib/pq/copy.go
сгенерированный
поставляемый
27
vendor/github.com/lib/pq/copy.go
сгенерированный
поставляемый
@@ -97,13 +97,13 @@ awaitCopyInResponse:
|
||||
err = parseError(r)
|
||||
case 'Z':
|
||||
if err == nil {
|
||||
cn.bad = true
|
||||
ci.setBad()
|
||||
errorf("unexpected ReadyForQuery in response to COPY")
|
||||
}
|
||||
cn.processReadyForQuery(r)
|
||||
return nil, err
|
||||
default:
|
||||
cn.bad = true
|
||||
ci.setBad()
|
||||
errorf("unknown response for copy query: %q", t)
|
||||
}
|
||||
}
|
||||
@@ -122,7 +122,7 @@ awaitCopyInResponse:
|
||||
cn.processReadyForQuery(r)
|
||||
return nil, err
|
||||
default:
|
||||
cn.bad = true
|
||||
ci.setBad()
|
||||
errorf("unknown response for CopyFail: %q", t)
|
||||
}
|
||||
}
|
||||
@@ -143,7 +143,7 @@ func (ci *copyin) resploop() {
|
||||
var r readBuf
|
||||
t, err := ci.cn.recvMessage(&r)
|
||||
if err != nil {
|
||||
ci.cn.bad = true
|
||||
ci.setBad()
|
||||
ci.setError(err)
|
||||
ci.done <- true
|
||||
return
|
||||
@@ -161,7 +161,7 @@ func (ci *copyin) resploop() {
|
||||
err := parseError(&r)
|
||||
ci.setError(err)
|
||||
default:
|
||||
ci.cn.bad = true
|
||||
ci.setBad()
|
||||
ci.setError(fmt.Errorf("unknown response during CopyIn: %q", t))
|
||||
ci.done <- true
|
||||
return
|
||||
@@ -169,6 +169,19 @@ func (ci *copyin) resploop() {
|
||||
}
|
||||
}
|
||||
|
||||
func (ci *copyin) setBad() {
|
||||
ci.Lock()
|
||||
ci.cn.bad = true
|
||||
ci.Unlock()
|
||||
}
|
||||
|
||||
func (ci *copyin) isBad() bool {
|
||||
ci.Lock()
|
||||
b := ci.cn.bad
|
||||
ci.Unlock()
|
||||
return b
|
||||
}
|
||||
|
||||
func (ci *copyin) isErrorSet() bool {
|
||||
ci.Lock()
|
||||
isSet := (ci.err != nil)
|
||||
@@ -206,7 +219,7 @@ func (ci *copyin) Exec(v []driver.Value) (r driver.Result, err error) {
|
||||
return nil, errCopyInClosed
|
||||
}
|
||||
|
||||
if ci.cn.bad {
|
||||
if ci.isBad() {
|
||||
return nil, driver.ErrBadConn
|
||||
}
|
||||
defer ci.cn.errRecover(&err)
|
||||
@@ -244,7 +257,7 @@ func (ci *copyin) Close() (err error) {
|
||||
}
|
||||
ci.closed = true
|
||||
|
||||
if ci.cn.bad {
|
||||
if ci.isBad() {
|
||||
return driver.ErrBadConn
|
||||
}
|
||||
defer ci.cn.errRecover(&err)
|
||||
|
||||
8
vendor/github.com/lib/pq/encode.go
сгенерированный
поставляемый
8
vendor/github.com/lib/pq/encode.go
сгенерированный
поставляемый
@@ -76,6 +76,12 @@ func binaryDecode(parameterStatus *parameterStatus, s []byte, typ oid.Oid) inter
|
||||
return int64(int32(binary.BigEndian.Uint32(s)))
|
||||
case oid.T_int2:
|
||||
return int64(int16(binary.BigEndian.Uint16(s)))
|
||||
case oid.T_uuid:
|
||||
b, err := decodeUUIDBinary(s)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
return b
|
||||
|
||||
default:
|
||||
errorf("don't know how to decode binary parameter of type %d", uint32(typ))
|
||||
@@ -471,7 +477,7 @@ func FormatTimestamp(t time.Time) []byte {
|
||||
t = t.AddDate((-t.Year())*2+1, 0, 0)
|
||||
bc = true
|
||||
}
|
||||
b := []byte(t.Format(time.RFC3339Nano))
|
||||
b := []byte(t.Format("2006-01-02 15:04:05.999999999Z07:00"))
|
||||
|
||||
_, offset := t.Zone()
|
||||
offset = offset % 60
|
||||
|
||||
46
vendor/github.com/lib/pq/encode_test.go
сгенерированный
поставляемый
46
vendor/github.com/lib/pq/encode_test.go
сгенерированный
поставляемый
@@ -141,22 +141,22 @@ var formatTimeTests = []struct {
|
||||
time time.Time
|
||||
expected string
|
||||
}{
|
||||
{time.Time{}, "0001-01-01T00:00:00Z"},
|
||||
{time.Date(2001, time.February, 3, 4, 5, 6, 123456789, time.FixedZone("", 0)), "2001-02-03T04:05:06.123456789Z"},
|
||||
{time.Date(2001, time.February, 3, 4, 5, 6, 123456789, time.FixedZone("", 2*60*60)), "2001-02-03T04:05:06.123456789+02:00"},
|
||||
{time.Date(2001, time.February, 3, 4, 5, 6, 123456789, time.FixedZone("", -6*60*60)), "2001-02-03T04:05:06.123456789-06:00"},
|
||||
{time.Date(2001, time.February, 3, 4, 5, 6, 0, time.FixedZone("", -(7*60*60+30*60+9))), "2001-02-03T04:05:06-07:30:09"},
|
||||
{time.Time{}, "0001-01-01 00:00:00Z"},
|
||||
{time.Date(2001, time.February, 3, 4, 5, 6, 123456789, time.FixedZone("", 0)), "2001-02-03 04:05:06.123456789Z"},
|
||||
{time.Date(2001, time.February, 3, 4, 5, 6, 123456789, time.FixedZone("", 2*60*60)), "2001-02-03 04:05:06.123456789+02:00"},
|
||||
{time.Date(2001, time.February, 3, 4, 5, 6, 123456789, time.FixedZone("", -6*60*60)), "2001-02-03 04:05:06.123456789-06:00"},
|
||||
{time.Date(2001, time.February, 3, 4, 5, 6, 0, time.FixedZone("", -(7*60*60+30*60+9))), "2001-02-03 04:05:06-07:30:09"},
|
||||
|
||||
{time.Date(1, time.February, 3, 4, 5, 6, 123456789, time.FixedZone("", 0)), "0001-02-03T04:05:06.123456789Z"},
|
||||
{time.Date(1, time.February, 3, 4, 5, 6, 123456789, time.FixedZone("", 2*60*60)), "0001-02-03T04:05:06.123456789+02:00"},
|
||||
{time.Date(1, time.February, 3, 4, 5, 6, 123456789, time.FixedZone("", -6*60*60)), "0001-02-03T04:05:06.123456789-06:00"},
|
||||
{time.Date(1, time.February, 3, 4, 5, 6, 123456789, time.FixedZone("", 0)), "0001-02-03 04:05:06.123456789Z"},
|
||||
{time.Date(1, time.February, 3, 4, 5, 6, 123456789, time.FixedZone("", 2*60*60)), "0001-02-03 04:05:06.123456789+02:00"},
|
||||
{time.Date(1, time.February, 3, 4, 5, 6, 123456789, time.FixedZone("", -6*60*60)), "0001-02-03 04:05:06.123456789-06:00"},
|
||||
|
||||
{time.Date(0, time.February, 3, 4, 5, 6, 123456789, time.FixedZone("", 0)), "0001-02-03T04:05:06.123456789Z BC"},
|
||||
{time.Date(0, time.February, 3, 4, 5, 6, 123456789, time.FixedZone("", 2*60*60)), "0001-02-03T04:05:06.123456789+02:00 BC"},
|
||||
{time.Date(0, time.February, 3, 4, 5, 6, 123456789, time.FixedZone("", -6*60*60)), "0001-02-03T04:05:06.123456789-06:00 BC"},
|
||||
{time.Date(0, time.February, 3, 4, 5, 6, 123456789, time.FixedZone("", 0)), "0001-02-03 04:05:06.123456789Z BC"},
|
||||
{time.Date(0, time.February, 3, 4, 5, 6, 123456789, time.FixedZone("", 2*60*60)), "0001-02-03 04:05:06.123456789+02:00 BC"},
|
||||
{time.Date(0, time.February, 3, 4, 5, 6, 123456789, time.FixedZone("", -6*60*60)), "0001-02-03 04:05:06.123456789-06:00 BC"},
|
||||
|
||||
{time.Date(1, time.February, 3, 4, 5, 6, 0, time.FixedZone("", -(7*60*60+30*60+9))), "0001-02-03T04:05:06-07:30:09"},
|
||||
{time.Date(0, time.February, 3, 4, 5, 6, 0, time.FixedZone("", -(7*60*60+30*60+9))), "0001-02-03T04:05:06-07:30:09 BC"},
|
||||
{time.Date(1, time.February, 3, 4, 5, 6, 0, time.FixedZone("", -(7*60*60+30*60+9))), "0001-02-03 04:05:06-07:30:09"},
|
||||
{time.Date(0, time.February, 3, 4, 5, 6, 0, time.FixedZone("", -(7*60*60+30*60+9))), "0001-02-03 04:05:06-07:30:09 BC"},
|
||||
}
|
||||
|
||||
func TestFormatTs(t *testing.T) {
|
||||
@@ -168,6 +168,26 @@ func TestFormatTs(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestFormatTsBackend(t *testing.T) {
|
||||
db := openTestConn(t)
|
||||
defer db.Close()
|
||||
|
||||
var str string
|
||||
err := db.QueryRow("SELECT '2001-02-03T04:05:06.007-08:09:10'::time::text").Scan(&str)
|
||||
if err == nil {
|
||||
t.Fatalf("PostgreSQL is accepting an ISO timestamp input for time")
|
||||
}
|
||||
|
||||
for i, tt := range formatTimeTests {
|
||||
for _, typ := range []string{"date", "time", "timetz", "timestamp", "timestamptz"} {
|
||||
err = db.QueryRow("SELECT $1::"+typ+"::text", tt.time).Scan(&str)
|
||||
if err != nil {
|
||||
t.Errorf("%d: incorrect time format for %v on the backend: %v", i, typ, err)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestTimestampWithTimeZone(t *testing.T) {
|
||||
db := openTestConn(t)
|
||||
defer db.Close()
|
||||
|
||||
99
vendor/github.com/lib/pq/go18_test.go
сгенерированный
поставляемый
99
vendor/github.com/lib/pq/go18_test.go
сгенерированный
поставляемый
@@ -2,7 +2,12 @@
|
||||
|
||||
package pq
|
||||
|
||||
import "testing"
|
||||
import (
|
||||
"context"
|
||||
"database/sql"
|
||||
"testing"
|
||||
"time"
|
||||
)
|
||||
|
||||
func TestMultipleSimpleQuery(t *testing.T) {
|
||||
db := openTestConn(t)
|
||||
@@ -66,3 +71,95 @@ func TestMultipleSimpleQuery(t *testing.T) {
|
||||
t.Fatal("unexpected result set")
|
||||
}
|
||||
}
|
||||
|
||||
func TestContextCancelExec(t *testing.T) {
|
||||
db := openTestConn(t)
|
||||
defer db.Close()
|
||||
|
||||
ctx, cancel := context.WithCancel(context.Background())
|
||||
|
||||
// Delay execution for just a bit until db.ExecContext has begun.
|
||||
go func() {
|
||||
time.Sleep(time.Millisecond * 10)
|
||||
cancel()
|
||||
}()
|
||||
|
||||
// Not canceled until after the exec has started.
|
||||
if _, err := db.ExecContext(ctx, "select pg_sleep(1)"); err == nil {
|
||||
t.Fatal("expected error")
|
||||
} else if err.Error() != "pq: canceling statement due to user request" {
|
||||
t.Fatalf("unexpected error: %s", err)
|
||||
}
|
||||
|
||||
// Context is already canceled, so error should come before execution.
|
||||
if _, err := db.ExecContext(ctx, "select pg_sleep(1)"); err == nil {
|
||||
t.Fatal("expected error")
|
||||
} else if err.Error() != "context canceled" {
|
||||
t.Fatalf("unexpected error: %s", err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestContextCancelQuery(t *testing.T) {
|
||||
db := openTestConn(t)
|
||||
defer db.Close()
|
||||
|
||||
ctx, cancel := context.WithCancel(context.Background())
|
||||
|
||||
// Delay execution for just a bit until db.QueryContext has begun.
|
||||
go func() {
|
||||
time.Sleep(time.Millisecond * 10)
|
||||
cancel()
|
||||
}()
|
||||
|
||||
// Not canceled until after the exec has started.
|
||||
if _, err := db.QueryContext(ctx, "select pg_sleep(1)"); err == nil {
|
||||
t.Fatal("expected error")
|
||||
} else if err.Error() != "pq: canceling statement due to user request" {
|
||||
t.Fatalf("unexpected error: %s", err)
|
||||
}
|
||||
|
||||
// Context is already canceled, so error should come before execution.
|
||||
if _, err := db.QueryContext(ctx, "select pg_sleep(1)"); err == nil {
|
||||
t.Fatal("expected error")
|
||||
} else if err.Error() != "context canceled" {
|
||||
t.Fatalf("unexpected error: %s", err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestContextCancelBegin(t *testing.T) {
|
||||
db := openTestConn(t)
|
||||
defer db.Close()
|
||||
|
||||
ctx, cancel := context.WithCancel(context.Background())
|
||||
tx, err := db.BeginTx(ctx, nil)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
// Delay execution for just a bit until tx.Exec has begun.
|
||||
go func() {
|
||||
time.Sleep(time.Millisecond * 10)
|
||||
cancel()
|
||||
}()
|
||||
|
||||
// Not canceled until after the exec has started.
|
||||
if _, err := tx.Exec("select pg_sleep(1)"); err == nil {
|
||||
t.Fatal("expected error")
|
||||
} else if err.Error() != "pq: canceling statement due to user request" {
|
||||
t.Fatalf("unexpected error: %s", err)
|
||||
}
|
||||
|
||||
// Transaction is canceled, so expect an error.
|
||||
if _, err := tx.Query("select pg_sleep(1)"); err == nil {
|
||||
t.Fatal("expected error")
|
||||
} else if err != sql.ErrTxDone {
|
||||
t.Fatalf("unexpected error: %s", err)
|
||||
}
|
||||
|
||||
// Context is canceled, so cannot begin a transaction.
|
||||
if _, err := db.BeginTx(ctx, nil); err == nil {
|
||||
t.Fatal("expected error")
|
||||
} else if err.Error() != "context canceled" {
|
||||
t.Fatalf("unexpected error: %s", err)
|
||||
}
|
||||
}
|
||||
|
||||
175
vendor/github.com/lib/pq/ssl.go
сгенерированный
поставляемый
Обычный файл
175
vendor/github.com/lib/pq/ssl.go
сгенерированный
поставляемый
Обычный файл
@@ -0,0 +1,175 @@
|
||||
package pq
|
||||
|
||||
import (
|
||||
"crypto/tls"
|
||||
"crypto/x509"
|
||||
"io/ioutil"
|
||||
"net"
|
||||
"os"
|
||||
"os/user"
|
||||
"path/filepath"
|
||||
)
|
||||
|
||||
// ssl generates a function to upgrade a net.Conn based on the "sslmode" and
|
||||
// related settings. The function is nil when no upgrade should take place.
|
||||
func ssl(o values) func(net.Conn) net.Conn {
|
||||
verifyCaOnly := false
|
||||
tlsConf := tls.Config{}
|
||||
switch mode := o.Get("sslmode"); mode {
|
||||
// "require" is the default.
|
||||
case "", "require":
|
||||
// We must skip TLS's own verification since it requires full
|
||||
// verification since Go 1.3.
|
||||
tlsConf.InsecureSkipVerify = true
|
||||
|
||||
// From http://www.postgresql.org/docs/current/static/libpq-ssl.html:
|
||||
// Note: For backwards compatibility with earlier versions of PostgreSQL, if a
|
||||
// root CA file exists, the behavior of sslmode=require will be the same as
|
||||
// that of verify-ca, meaning the server certificate is validated against the
|
||||
// CA. Relying on this behavior is discouraged, and applications that need
|
||||
// certificate validation should always use verify-ca or verify-full.
|
||||
if _, err := os.Stat(o.Get("sslrootcert")); err == nil {
|
||||
verifyCaOnly = true
|
||||
} else {
|
||||
o.Set("sslrootcert", "")
|
||||
}
|
||||
case "verify-ca":
|
||||
// We must skip TLS's own verification since it requires full
|
||||
// verification since Go 1.3.
|
||||
tlsConf.InsecureSkipVerify = true
|
||||
verifyCaOnly = true
|
||||
case "verify-full":
|
||||
tlsConf.ServerName = o.Get("host")
|
||||
case "disable":
|
||||
return nil
|
||||
default:
|
||||
errorf(`unsupported sslmode %q; only "require" (default), "verify-full", "verify-ca", and "disable" supported`, mode)
|
||||
}
|
||||
|
||||
sslClientCertificates(&tlsConf, o)
|
||||
sslCertificateAuthority(&tlsConf, o)
|
||||
sslRenegotiation(&tlsConf)
|
||||
|
||||
return func(conn net.Conn) net.Conn {
|
||||
client := tls.Client(conn, &tlsConf)
|
||||
if verifyCaOnly {
|
||||
sslVerifyCertificateAuthority(client, &tlsConf)
|
||||
}
|
||||
return client
|
||||
}
|
||||
}
|
||||
|
||||
// sslClientCertificates adds the certificate specified in the "sslcert" and
|
||||
// "sslkey" settings, or if they aren't set, from the .postgresql directory
|
||||
// in the user's home directory. The configured files must exist and have
|
||||
// the correct permissions.
|
||||
func sslClientCertificates(tlsConf *tls.Config, o values) {
|
||||
sslkey := o.Get("sslkey")
|
||||
sslcert := o.Get("sslcert")
|
||||
|
||||
var cinfo, kinfo os.FileInfo
|
||||
var err error
|
||||
|
||||
if sslcert != "" && sslkey != "" {
|
||||
// Check that both files exist. Note that we don't do any more extensive
|
||||
// checks than this (such as checking that the paths aren't directories);
|
||||
// LoadX509KeyPair() will take care of the rest.
|
||||
cinfo, err = os.Stat(sslcert)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
kinfo, err = os.Stat(sslkey)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
} else {
|
||||
// Automatically find certificates from ~/.postgresql
|
||||
sslcert, sslkey, cinfo, kinfo = sslHomeCertificates()
|
||||
|
||||
if cinfo == nil || kinfo == nil {
|
||||
// No certificates to load
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
// The files must also have the correct permissions
|
||||
sslCertificatePermissions(cinfo, kinfo)
|
||||
|
||||
cert, err := tls.LoadX509KeyPair(sslcert, sslkey)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
tlsConf.Certificates = []tls.Certificate{cert}
|
||||
}
|
||||
|
||||
// sslCertificateAuthority adds the RootCA specified in the "sslrootcert" setting.
|
||||
func sslCertificateAuthority(tlsConf *tls.Config, o values) {
|
||||
if sslrootcert := o.Get("sslrootcert"); sslrootcert != "" {
|
||||
tlsConf.RootCAs = x509.NewCertPool()
|
||||
|
||||
cert, err := ioutil.ReadFile(sslrootcert)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
ok := tlsConf.RootCAs.AppendCertsFromPEM(cert)
|
||||
if !ok {
|
||||
errorf("couldn't parse pem in sslrootcert")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// sslHomeCertificates returns the path and stats of certificates in the current
|
||||
// user's home directory.
|
||||
func sslHomeCertificates() (cert, key string, cinfo, kinfo os.FileInfo) {
|
||||
user, err := user.Current()
|
||||
|
||||
if err != nil {
|
||||
// user.Current() might fail when cross-compiling. We have to ignore the
|
||||
// error and continue without client certificates, since we wouldn't know
|
||||
// from where to load them.
|
||||
return
|
||||
}
|
||||
|
||||
cert = filepath.Join(user.HomeDir, ".postgresql", "postgresql.crt")
|
||||
key = filepath.Join(user.HomeDir, ".postgresql", "postgresql.key")
|
||||
|
||||
cinfo, err = os.Stat(cert)
|
||||
if err != nil {
|
||||
cinfo = nil
|
||||
}
|
||||
|
||||
kinfo, err = os.Stat(key)
|
||||
if err != nil {
|
||||
kinfo = nil
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
// sslVerifyCertificateAuthority carries out a TLS handshake to the server and
|
||||
// verifies the presented certificate against the CA, i.e. the one specified in
|
||||
// sslrootcert or the system CA if sslrootcert was not specified.
|
||||
func sslVerifyCertificateAuthority(client *tls.Conn, tlsConf *tls.Config) {
|
||||
err := client.Handshake()
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
certs := client.ConnectionState().PeerCertificates
|
||||
opts := x509.VerifyOptions{
|
||||
DNSName: client.ConnectionState().ServerName,
|
||||
Intermediates: x509.NewCertPool(),
|
||||
Roots: tlsConf.RootCAs,
|
||||
}
|
||||
for i, cert := range certs {
|
||||
if i == 0 {
|
||||
continue
|
||||
}
|
||||
opts.Intermediates.AddCert(cert)
|
||||
}
|
||||
_, err = certs[0].Verify(opts)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
}
|
||||
14
vendor/github.com/lib/pq/ssl_go1.7.go
сгенерированный
поставляемый
Обычный файл
14
vendor/github.com/lib/pq/ssl_go1.7.go
сгенерированный
поставляемый
Обычный файл
@@ -0,0 +1,14 @@
|
||||
// +build go1.7
|
||||
|
||||
package pq
|
||||
|
||||
import "crypto/tls"
|
||||
|
||||
// Accept renegotiation requests initiated by the backend.
|
||||
//
|
||||
// Renegotiation was deprecated then removed from PostgreSQL 9.5, but
|
||||
// the default configuration of older versions has it enabled. Redshift
|
||||
// also initiates renegotiations and cannot be reconfigured.
|
||||
func sslRenegotiation(conf *tls.Config) {
|
||||
conf.Renegotiation = tls.RenegotiateFreelyAsClient
|
||||
}
|
||||
16
vendor/github.com/lib/pq/ssl_permissions.go
сгенерированный
поставляемый
Обычный файл
16
vendor/github.com/lib/pq/ssl_permissions.go
сгенерированный
поставляемый
Обычный файл
@@ -0,0 +1,16 @@
|
||||
// +build !windows
|
||||
|
||||
package pq
|
||||
|
||||
import "os"
|
||||
|
||||
// sslCertificatePermissions checks the permissions on user-supplied certificate
|
||||
// files. The key file should have very little access.
|
||||
//
|
||||
// libpq does not check key file permissions on Windows.
|
||||
func sslCertificatePermissions(cert, key os.FileInfo) {
|
||||
kmode := key.Mode()
|
||||
if kmode != kmode&0600 {
|
||||
panic(ErrSSLKeyHasWorldPermissions)
|
||||
}
|
||||
}
|
||||
8
vendor/github.com/lib/pq/ssl_renegotiation.go
сгенерированный
поставляемый
Обычный файл
8
vendor/github.com/lib/pq/ssl_renegotiation.go
сгенерированный
поставляемый
Обычный файл
@@ -0,0 +1,8 @@
|
||||
// +build !go1.7
|
||||
|
||||
package pq
|
||||
|
||||
import "crypto/tls"
|
||||
|
||||
// Renegotiation is not supported by crypto/tls until Go 1.7.
|
||||
func sslRenegotiation(*tls.Config) {}
|
||||
9
vendor/github.com/lib/pq/ssl_windows.go
сгенерированный
поставляемый
Обычный файл
9
vendor/github.com/lib/pq/ssl_windows.go
сгенерированный
поставляемый
Обычный файл
@@ -0,0 +1,9 @@
|
||||
// +build windows
|
||||
|
||||
package pq
|
||||
|
||||
import "os"
|
||||
|
||||
// sslCertificatePermissions checks the permissions on user-supplied certificate
|
||||
// files. In libpq, this is a no-op on Windows.
|
||||
func sslCertificatePermissions(cert, key os.FileInfo) {}
|
||||
23
vendor/github.com/lib/pq/uuid.go
сгенерированный
поставляемый
Обычный файл
23
vendor/github.com/lib/pq/uuid.go
сгенерированный
поставляемый
Обычный файл
@@ -0,0 +1,23 @@
|
||||
package pq
|
||||
|
||||
import (
|
||||
"encoding/hex"
|
||||
"fmt"
|
||||
)
|
||||
|
||||
// decodeUUIDBinary interprets the binary format of a uuid, returning it in text format.
|
||||
func decodeUUIDBinary(src []byte) ([]byte, error) {
|
||||
if len(src) != 16 {
|
||||
return nil, fmt.Errorf("pq: unable to decode uuid; bad length: %d", len(src))
|
||||
}
|
||||
|
||||
dst := make([]byte, 36)
|
||||
dst[8], dst[13], dst[18], dst[23] = '-', '-', '-', '-'
|
||||
hex.Encode(dst[0:], src[0:4])
|
||||
hex.Encode(dst[9:], src[4:6])
|
||||
hex.Encode(dst[14:], src[6:8])
|
||||
hex.Encode(dst[19:], src[8:10])
|
||||
hex.Encode(dst[24:], src[10:16])
|
||||
|
||||
return dst, nil
|
||||
}
|
||||
46
vendor/github.com/lib/pq/uuid_test.go
сгенерированный
поставляемый
Обычный файл
46
vendor/github.com/lib/pq/uuid_test.go
сгенерированный
поставляемый
Обычный файл
@@ -0,0 +1,46 @@
|
||||
package pq
|
||||
|
||||
import (
|
||||
"reflect"
|
||||
"strings"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestDecodeUUIDBinaryError(t *testing.T) {
|
||||
t.Parallel()
|
||||
_, err := decodeUUIDBinary([]byte{0x12, 0x34})
|
||||
|
||||
if err == nil {
|
||||
t.Fatal("Expected error, got none")
|
||||
}
|
||||
if !strings.HasPrefix(err.Error(), "pq:") {
|
||||
t.Errorf("Expected error to start with %q, got %q", "pq:", err.Error())
|
||||
}
|
||||
if !strings.Contains(err.Error(), "bad length: 2") {
|
||||
t.Errorf("Expected error to contain length, got %q", err.Error())
|
||||
}
|
||||
}
|
||||
|
||||
func BenchmarkDecodeUUIDBinary(b *testing.B) {
|
||||
x := []byte{0x03, 0xa3, 0x52, 0x2f, 0x89, 0x28, 0x49, 0x87, 0x84, 0xd6, 0x93, 0x7b, 0x36, 0xec, 0x27, 0x6f}
|
||||
|
||||
for i := 0; i < b.N; i++ {
|
||||
decodeUUIDBinary(x)
|
||||
}
|
||||
}
|
||||
|
||||
func TestDecodeUUIDBackend(t *testing.T) {
|
||||
db := openTestConn(t)
|
||||
defer db.Close()
|
||||
|
||||
var s string = "a0ecc91d-a13f-4fe4-9fce-7e09777cc70a"
|
||||
var scanned interface{}
|
||||
|
||||
err := db.QueryRow(`SELECT $1::uuid`, s).Scan(&scanned)
|
||||
if err != nil {
|
||||
t.Fatalf("Expected no error, got %v", err)
|
||||
}
|
||||
if !reflect.DeepEqual(scanned, []byte(s)) {
|
||||
t.Errorf("Expected []byte(%q), got %T(%q)", s, scanned, scanned)
|
||||
}
|
||||
}
|
||||
Ссылка в новой задаче
Block a user