123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131 |
- // 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/google/pprof/pkg/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)
- }
|