forked from sourcegraph/sourcegraph-public-snapshot
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathexternal.go
More file actions
97 lines (79 loc) · 2.63 KB
/
external.go
File metadata and controls
97 lines (79 loc) · 2.63 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
package httpcli
import (
"context"
"crypto/tls"
"crypto/x509"
"net/http"
"reflect"
"sync"
"go.opentelemetry.io/otel/attribute"
"github.com/sourcegraph/sourcegraph/internal/trace"
"github.com/sourcegraph/sourcegraph/schema"
)
type externalTransport struct {
base *http.Transport
mu sync.RWMutex
config *schema.TlsExternal
effective *http.Transport
}
var tlsExternalConfig struct {
sync.RWMutex
*schema.TlsExternal
}
// SetTLSExternalConfig is called by the conf package whenever TLSExternalConfig changes.
// This is needed to avoid circular imports.
func SetTLSExternalConfig(c *schema.TlsExternal) {
tlsExternalConfig.Lock()
tlsExternalConfig.TlsExternal = c
tlsExternalConfig.Unlock()
}
// TLSExternalConfig returns the current value of the global TLS external config.
func TLSExternalConfig() *schema.TlsExternal {
tlsExternalConfig.RLock()
defer tlsExternalConfig.RUnlock()
return tlsExternalConfig.TlsExternal
}
func (t *externalTransport) RoundTrip(r *http.Request) (*http.Response, error) {
t.mu.RLock()
config, effective := t.config, t.effective
t.mu.RUnlock()
if current := TLSExternalConfig(); current == nil {
return t.base.RoundTrip(r)
} else if !reflect.DeepEqual(config, current) {
effective = t.update(r.Context(), current)
}
return effective.RoundTrip(r)
}
func (t *externalTransport) update(ctx context.Context, config *schema.TlsExternal) *http.Transport {
// No function calls here use the context further
tr, _ := trace.New(ctx, "externalTransport", "update")
defer tr.Finish()
t.mu.Lock()
defer t.mu.Unlock()
effective := t.base.Clone()
if effective.TLSClientConfig == nil {
effective.TLSClientConfig = new(tls.Config)
}
effective.TLSClientConfig.InsecureSkipVerify = config.InsecureSkipVerify
for _, cert := range config.Certificates {
// There is no exposed Clone function for CertPools. So if a certificate
// is removed it will continue to be accepted since we are mutating base's
// RootCAs. This is an acceptable tradeoff since it would be quite tricky
// to avoid this.
if effective.TLSClientConfig.RootCAs == nil {
pool, err := x509.SystemCertPool() // safe to mutate, a clone is returned
if err != nil {
tr.AddEvent("failed to load SystemCertPool",
attribute.String("error", err.Error()),
attribute.String("warning", "communication with external HTTPS APIs may fail"))
pool = x509.NewCertPool()
}
effective.TLSClientConfig.RootCAs = pool
}
// TODO(keegancsmith) ensure we validate these certs somewhere
effective.TLSClientConfig.RootCAs.AppendCertsFromPEM([]byte(cert))
}
t.config = config
t.effective = effective
return effective
}