/
transport.go
131 lines (116 loc) · 3.78 KB
/
transport.go
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
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
// Copyright 2018 Google Inc. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
// Package transport provides a mechanism to send requests with https cert,
// key, and CA.
package transport
import (
"crypto/tls"
"crypto/x509"
"fmt"
"io/ioutil"
"net/http"
"sync"
"github.com/Kolo7/pprof-tool/internal/plugin"
)
type transport struct {
cert *string
key *string
ca *string
caCertPool *x509.CertPool
certs []tls.Certificate
initOnce sync.Once
initErr error
}
const extraUsage = ` -tls_cert TLS client certificate file for fetching profile and symbols
-tls_key TLS private key file for fetching profile and symbols
-tls_ca TLS CA certs file for fetching profile and symbols`
// New returns a round tripper for making requests with the
// specified cert, key, and ca. The flags tls_cert, tls_key, and tls_ca are
// added to the flagset to allow a user to specify the cert, key, and ca. If
// the flagset is nil, no flags will be added, and users will not be able to
// use these flags.
func New(flagset plugin.FlagSet) http.RoundTripper {
if flagset == nil {
return &transport{}
}
flagset.AddExtraUsage(extraUsage)
return &transport{
cert: flagset.String("tls_cert", "", "TLS client certificate file for fetching profile and symbols"),
key: flagset.String("tls_key", "", "TLS private key file for fetching profile and symbols"),
ca: flagset.String("tls_ca", "", "TLS CA certs file for fetching profile and symbols"),
}
}
// initialize uses the cert, key, and ca to initialize the certs
// to use these when making requests.
func (tr *transport) initialize() error {
var cert, key, ca string
if tr.cert != nil {
cert = *tr.cert
}
if tr.key != nil {
key = *tr.key
}
if tr.ca != nil {
ca = *tr.ca
}
if cert != "" && key != "" {
tlsCert, err := tls.LoadX509KeyPair(cert, key)
if err != nil {
return fmt.Errorf("could not load certificate/key pair specified by -tls_cert and -tls_key: %v", err)
}
tr.certs = []tls.Certificate{tlsCert}
} else if cert == "" && key != "" {
return fmt.Errorf("-tls_key is specified, so -tls_cert must also be specified")
} else if cert != "" && key == "" {
return fmt.Errorf("-tls_cert is specified, so -tls_key must also be specified")
}
if ca != "" {
caCertPool := x509.NewCertPool()
caCert, err := ioutil.ReadFile(ca)
if err != nil {
return fmt.Errorf("could not load CA specified by -tls_ca: %v", err)
}
caCertPool.AppendCertsFromPEM(caCert)
tr.caCertPool = caCertPool
}
return nil
}
// RoundTrip executes a single HTTP transaction, returning
// a Response for the provided Request.
func (tr *transport) RoundTrip(req *http.Request) (*http.Response, error) {
tr.initOnce.Do(func() {
tr.initErr = tr.initialize()
})
if tr.initErr != nil {
return nil, tr.initErr
}
tlsConfig := &tls.Config{
RootCAs: tr.caCertPool,
Certificates: tr.certs,
}
if req.URL.Scheme == "https+insecure" {
// Make shallow copy of request, and req.URL, so the request's URL can be
// modified.
r := *req
*r.URL = *req.URL
req = &r
tlsConfig.InsecureSkipVerify = true
req.URL.Scheme = "https"
}
transport := http.Transport{
Proxy: http.ProxyFromEnvironment,
TLSClientConfig: tlsConfig,
}
return transport.RoundTrip(req)
}