Fix managed http/https transport failures #858
61
http.go
61
http.go
|
@ -1,6 +1,8 @@
|
|||
package git
|
||||
|
||||
import (
|
||||
"crypto/tls"
|
||||
"crypto/x509"
|
||||
"errors"
|
||||
"fmt"
|
||||
"io"
|
||||
|
@ -190,8 +192,19 @@ func (self *httpSmartSubtransportStream) sendRequest() error {
|
|||
|
||||
var resp *http.Response
|
||||
var err error
|
||||
var userName string
|
||||
var password string
|
||||
|
||||
// Obtain the credentials and use them.
|
||||
cred, err := self.owner.transport.SmartCredentials("", CredentialTypeUserpassPlaintext)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer cred.Free()
|
||||
|
||||
userName, password, err := cred.GetUserpassPlaintext()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
for {
|
||||
req := &http.Request{
|
||||
Method: self.req.Method,
|
||||
|
@ -204,7 +217,32 @@ func (self *httpSmartSubtransportStream) sendRequest() error {
|
|||
}
|
||||
|
||||
req.SetBasicAuth(userName, password)
|
||||
resp, err = http.DefaultClient.Do(req)
|
||||
|
||||
c := http.Client{}
|
||||
|
||||
cap := x509.NewCertPool()
|
||||
|
||||
// NOTE: self.req.URL.Host returns only host without port. To be
|
||||
// able to fetch the correct certs from the global certs, parse again
|
||||
// and get host+port with url.Host.
|
||||
u, err := url.Parse(self.req.URL.String())
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to parse URL: %v", err)
|
||||
}
|
||||
|
||||
// Use CA cert if found.
|
||||
if cert, found := globalCACertPool.certPool[u.Host]; found {
|
||||
if ok := cap.AppendCertsFromPEM(cert); !ok {
|
||||
return fmt.Errorf("failed to parse CA cert")
|
||||
}
|
||||
c.Transport = &http.Transport{
|
||||
TLSClientConfig: &tls.Config{
|
||||
RootCAs: cap,
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
resp, err = c.Do(req)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
@ -213,23 +251,6 @@ func (self *httpSmartSubtransportStream) sendRequest() error {
|
|||
break
|
||||
}
|
||||
|
||||
if resp.StatusCode == http.StatusUnauthorized {
|
||||
resp.Body.Close()
|
||||
|
||||
cred, err := self.owner.transport.SmartCredentials("", CredentialTypeUserpassPlaintext)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer cred.Free()
|
||||
|
||||
userName, password, err = cred.GetUserpassPlaintext()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
continue
|
||||
}
|
||||
|
||||
// Any other error we treat as a hard error and punt back to the caller
|
||||
resp.Body.Close()
|
||||
return fmt.Errorf("Unhandled HTTP error %s", resp.Status)
|
||||
|
|
31
transport.go
31
transport.go
|
@ -24,6 +24,7 @@ import "C"
|
|||
import (
|
||||
"fmt"
|
||||
"io"
|
||||
"net/url"
|
||||
"reflect"
|
||||
"runtime"
|
||||
"sync"
|
||||
|
@ -39,8 +40,38 @@ var (
|
|||
}{
|
||||
transports: make(map[string]*RegisteredSmartTransport),
|
||||
}
|
||||
// globalCACertPool is a mapping of global CA certs used by git2go-managed
|
||||
// transports. The map's key is hostname+port and the value is a
|
||||
// corresponding CA cert.
|
||||
// Since the git2go-managed transports aren't public, this can be used to
|
||||
// provide certs to the subtransports that can be looked up for a given
|
||||
// host.
|
||||
globalCACertPool = struct {
|
||||
sync.Mutex
|
||||
certPool map[string][]byte
|
||||
}{
|
||||
certPool: make(map[string][]byte),
|
||||
}
|
||||
)
|
||||
|
||||
// RegisterCACerts registers CA cert associated with an address in the
|
||||
// globalCACertPool.
|
||||
func RegisterCACerts(address string, caBundle []byte) error {
|
||||
globalCACertPool.Lock()
|
||||
defer globalCACertPool.Unlock()
|
||||
// Ignore empty CA bundles.
|
||||
if len(caBundle) == 0 {
|
||||
return nil
|
||||
}
|
||||
u, err := url.Parse(address)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
// Store the certificate based on host+port, e.g.: 127.0.0.1:42107.
|
||||
globalCACertPool.certPool[u.Host] = caBundle
|
||||
return nil
|
||||
}
|
||||
|
||||
// unregisterManagedTransports unregisters all git2go-managed transports.
|
||||
func unregisterManagedTransports() error {
|
||||
globalRegisteredSmartTransports.Lock()
|
||||
|
|
Loading…
Reference in New Issue