func (c *Client) SetLimiter(rateLimit float64, burst int) {
	c.modifyLock.RLock()
	defer c.modifyLock.RUnlock()
	c.config.modifyLock.Lock()
	defer c.config.modifyLock.Unlock()
	c.config.Limiter = rate.NewLimiter(rate.Limit(rateLimit), burst)
}
SetLimiter will set the rate limiter for this client.
This method is thread-safe.
rateLimit and burst are specified according to https://godoc.org/golang.org/x/time/rate#NewLimiter
package api
import (
	"context"
	"crypto/tls"
	"fmt"
	"net"
	"net/http"
	"net/url"
	"os"
	"path"
	"strconv"
	"strings"
	"sync"
	"time"
	"unicode"
	"github.com/hashicorp/errwrap"
	cleanhttp "github.com/hashicorp/go-cleanhttp"
	retryablehttp "github.com/hashicorp/go-retryablehttp"
	rootcerts "github.com/hashicorp/go-rootcerts"
	"github.com/hashicorp/vault/sdk/helper/consts"
	"github.com/hashicorp/vault/sdk/helper/parseutil"
	"golang.org/x/net/http2"
	"golang.org/x/time/rate"
)
const EnvVaultAddress = "VAULT_ADDR"
const EnvVaultAgentAddr = "VAULT_AGENT_ADDR"
const EnvVaultCACert = "VAULT_CACERT"
const EnvVaultCAPath = "VAULT_CAPATH"
const EnvVaultClientCert = "VAULT_CLIENT_CERT"
const EnvVaultClientKey = "VAULT_CLIENT_KEY"
const EnvVaultClientTimeout = "VAULT_CLIENT_TIMEOUT"
const EnvVaultSRVLookup = "VAULT_SRV_LOOKUP"
const EnvVaultSkipVerify = "VAULT_SKIP_VERIFY"
const EnvVaultNamespace = "VAULT_NAMESPACE"
const EnvVaultTLSServerName = "VAULT_TLS_SERVER_NAME"
const EnvVaultWrapTTL = "VAULT_WRAP_TTL"
const EnvVaultMaxRetries = "VAULT_MAX_RETRIES"
const EnvVaultToken = "VAULT_TOKEN"
const EnvVaultMFA = "VAULT_MFA"
const EnvRateLimit = "VAULT_RATE_LIMIT"
const EnvVaultAgentAddress = "VAULT_AGENT_ADDR"
const EnvVaultInsecure = "VAULT_SKIP_VERIFY"
type WrappingLookupFunc func(operation, path string) string
type Config struct {
	modifyLock sync.RWMutex
	Address string
	AgentAddress string
	HttpClient *http.Client
	MaxRetries int
	Timeout time.Duration
	Error error
	Backoff retryablehttp.Backoff
	CheckRetry retryablehttp.CheckRetry
	Limiter *rate.Limiter
	OutputCurlString bool
	SRVLookup bool
}
type TLSConfig struct {
	CACert string
	CAPath string
	ClientCert string
	ClientKey string
	TLSServerName string
	Insecure bool
}
func DefaultConfig() *Config {
	config := &Config{
		Address:    "https://127.0.0.1:8200",
		HttpClient: cleanhttp.DefaultPooledClient(),
		Timeout:    time.Second * 60,
		MaxRetries: 2,
		Backoff:    retryablehttp.LinearJitterBackoff,
	}
	transport := config.HttpClient.Transport.(*http.Transport)
	transport.TLSHandshakeTimeout = 10 * time.Second
	transport.TLSClientConfig = &tls.Config{
		MinVersion: tls.VersionTLS12,
	}
	if err := http2.ConfigureTransport(transport); err != nil {
		config.Error = err
		return config
	}
	if err := config.ReadEnvironment(); err != nil {
		config.Error = err
		return config
	}
	config.HttpClient.CheckRedirect = func(req *http.Request, via []*http.Request) error {
		return http.ErrUseLastResponse
	}
	return config
}
func (c *Config) ConfigureTLS(t *TLSConfig) error {
	if c.HttpClient == nil {
		c.HttpClient = DefaultConfig().HttpClient
	}
	clientTLSConfig := c.HttpClient.Transport.(*http.Transport).TLSClientConfig
	var clientCert tls.Certificate
	foundClientCert := false
	switch {
	case t.ClientCert != "" && t.ClientKey != "":
		var err error
		clientCert, err = tls.LoadX509KeyPair(t.ClientCert, t.ClientKey)
		if err != nil {
			return err
		}
		foundClientCert = true
	case t.ClientCert != "" || t.ClientKey != "":
		return fmt.Errorf("both client cert and client key must be provided")
	}
	if t.CACert != "" || t.CAPath != "" {
		rootConfig := &rootcerts.Config{
			CAFile: t.CACert,
			CAPath: t.CAPath,
		}
		if err := rootcerts.ConfigureTLS(clientTLSConfig, rootConfig); err != nil {
			return err
		}
	}
	if t.Insecure {
		clientTLSConfig.InsecureSkipVerify = true
	}
	if foundClientCert {
		clientTLSConfig.GetClientCertificate = func(*tls.CertificateRequestInfo) (*tls.Certificate, error) {
			return &clientCert, nil
		}
	}
	if t.TLSServerName != "" {
		clientTLSConfig.ServerName = t.TLSServerName
	}
	return nil
}
func (c *Config) ReadEnvironment() error {
	var envAddress string
	var envAgentAddress string
	var envCACert string
	var envCAPath string
	var envClientCert string
	var envClientKey string
	var envClientTimeout time.Duration
	var envInsecure bool
	var envTLSServerName string
	var envMaxRetries *uint64
	var envSRVLookup bool
	var limit *rate.Limiter
	if v := os.Getenv(EnvVaultAddress); v != "" {
		envAddress = v
	}
	if v := os.Getenv(EnvVaultAgentAddr); v != "" {
		envAgentAddress = v
	} else if v := os.Getenv(EnvVaultAgentAddress); v != "" {
		envAgentAddress = v
	}
	if v := os.Getenv(EnvVaultMaxRetries); v != "" {
		maxRetries, err := strconv.ParseUint(v, 10, 32)
		if err != nil {
			return err
		}
		envMaxRetries = &maxRetries
	}
	if v := os.Getenv(EnvVaultCACert); v != "" {
		envCACert = v
	}
	if v := os.Getenv(EnvVaultCAPath); v != "" {
		envCAPath = v
	}
	if v := os.Getenv(EnvVaultClientCert); v != "" {
		envClientCert = v
	}
	if v := os.Getenv(EnvVaultClientKey); v != "" {
		envClientKey = v
	}
	if v := os.Getenv(EnvRateLimit); v != "" {
		rateLimit, burstLimit, err := parseRateLimit(v)
		if err != nil {
			return err
		}
		limit = rate.NewLimiter(rate.Limit(rateLimit), burstLimit)
	}
	if t := os.Getenv(EnvVaultClientTimeout); t != "" {
		clientTimeout, err := parseutil.ParseDurationSecond(t)
		if err != nil {
			return fmt.Errorf("could not parse %q", EnvVaultClientTimeout)
		}
		envClientTimeout = clientTimeout
	}
	if v := os.Getenv(EnvVaultSkipVerify); v != "" {
		var err error
		envInsecure, err = strconv.ParseBool(v)
		if err != nil {
			return fmt.Errorf("could not parse VAULT_SKIP_VERIFY")
		}
	} else if v := os.Getenv(EnvVaultInsecure); v != "" {
		var err error
		envInsecure, err = strconv.ParseBool(v)
		if err != nil {
			return fmt.Errorf("could not parse VAULT_INSECURE")
		}
	}
	if v := os.Getenv(EnvVaultSRVLookup); v != "" {
		var err error
		envSRVLookup, err = strconv.ParseBool(v)
		if err != nil {
			return fmt.Errorf("could not parse %s", EnvVaultSRVLookup)
		}
	}
	if v := os.Getenv(EnvVaultTLSServerName); v != "" {
		envTLSServerName = v
	}
	t := &TLSConfig{
		CACert:        envCACert,
		CAPath:        envCAPath,
		ClientCert:    envClientCert,
		ClientKey:     envClientKey,
		TLSServerName: envTLSServerName,
		Insecure:      envInsecure,
	}
	c.modifyLock.Lock()
	defer c.modifyLock.Unlock()
	c.SRVLookup = envSRVLookup
	c.Limiter = limit
	if err := c.ConfigureTLS(t); err != nil {
		return err
	}
	if envAddress != "" {
		c.Address = envAddress
	}
	if envAgentAddress != "" {
		c.AgentAddress = envAgentAddress
	}
	if envMaxRetries != nil {
		c.MaxRetries = int(*envMaxRetries)
	}
	if envClientTimeout != 0 {
		c.Timeout = envClientTimeout
	}
	return nil
}
func parseRateLimit(val string) (rate float64, burst int, err error) {
	_, err = fmt.Sscanf(val, "%f:%d", &rate, &burst)
	if err != nil {
		rate, err = strconv.ParseFloat(val, 64)
		if err != nil {
			err = fmt.Errorf("%v was provided but incorrectly formatted", EnvRateLimit)
		}
		burst = int(rate)
	}
	return rate, burst, err
}
type Client struct {
	modifyLock         sync.RWMutex
	addr               *url.URL
	config             *Config
	token              string
	headers            http.Header
	wrappingLookupFunc WrappingLookupFunc
	mfaCreds           []string
	policyOverride     bool
	requestCallbacks   []RequestCallback
	responseCallbacks  []ResponseCallback
}
func NewClient(c *Config) (*Client, error) {
	def := DefaultConfig()
	if def == nil {
		return nil, fmt.Errorf("could not create/read default configuration")
	}
	if def.Error != nil {
		return nil, errwrap.Wrapf("error encountered setting up default configuration: {{err}}", def.Error)
	}
	if c == nil {
		c = def
	}
	c.modifyLock.Lock()
	defer c.modifyLock.Unlock()
	if c.HttpClient == nil {
		c.HttpClient = def.HttpClient
	}
	if c.HttpClient.Transport == nil {
		c.HttpClient.Transport = def.HttpClient.Transport
	}
	address := c.Address
	if c.AgentAddress != "" {
		address = c.AgentAddress
	}
	u, err := url.Parse(address)
	if err != nil {
		return nil, err
	}
	if strings.HasPrefix(address, "unix://") {
		socket := strings.TrimPrefix(address, "unix://")
		transport := c.HttpClient.Transport.(*http.Transport)
		transport.DialContext = func(context.Context, string, string) (net.Conn, error) {
			return net.Dial("unix", socket)
		}
		u.Scheme = "http"
		u.Host = socket
		u.Path = ""
	}
	client := &Client{
		addr:    u,
		config:  c,
		headers: make(http.Header),
	}
	client.headers[consts.RequestHeaderName] = []string{"true"}
	if token := os.Getenv(EnvVaultToken); token != "" {
		client.token = token
	}
	if namespace := os.Getenv(EnvVaultNamespace); namespace != "" {
		client.setNamespace(namespace)
	}
	return client, nil
}
func (c *Client) CloneConfig() *Config {
	c.modifyLock.RLock()
	defer c.modifyLock.RUnlock()
	newConfig := DefaultConfig()
	newConfig.Address = c.config.Address
	newConfig.AgentAddress = c.config.AgentAddress
	newConfig.MaxRetries = c.config.MaxRetries
	newConfig.Timeout = c.config.Timeout
	newConfig.Backoff = c.config.Backoff
	newConfig.CheckRetry = c.config.CheckRetry
	newConfig.Limiter = c.config.Limiter
	newConfig.OutputCurlString = c.config.OutputCurlString
	newConfig.SRVLookup = c.config.SRVLookup
	newClient := *c.config.HttpClient
	newConfig.HttpClient = &newClient
	return newConfig
}
func (c *Client) SetAddress(addr string) error {
	c.modifyLock.Lock()
	defer c.modifyLock.Unlock()
	parsedAddr, err := url.Parse(addr)
	if err != nil {
		return errwrap.Wrapf("failed to set address: {{err}}", err)
	}
	c.config.modifyLock.Lock()
	c.config.Address = addr
	c.config.modifyLock.Unlock()
	c.addr = parsedAddr
	return nil
}
func (c *Client) Address() string {
	c.modifyLock.RLock()
	defer c.modifyLock.RUnlock()
	return c.addr.String()
}