github.com/netdata/go.d.plugin@v0.58.1/pkg/web/client.go (about) 1 // SPDX-License-Identifier: GPL-3.0-or-later 2 3 package web 4 5 import ( 6 "errors" 7 "fmt" 8 "net" 9 "net/http" 10 "net/url" 11 12 "github.com/netdata/go.d.plugin/pkg/tlscfg" 13 ) 14 15 // ErrRedirectAttempted indicates that a redirect occurred. 16 var ErrRedirectAttempted = errors.New("redirect") 17 18 // Client is the configuration of the HTTP client. 19 // This structure is not intended to be used directly as part of a module's configuration. 20 // Supported configuration file formats: YAML. 21 type Client struct { 22 // Timeout specifies a time limit for requests made by this Client. 23 // Default (zero value) is no timeout. Must be set before http.Client creation. 24 Timeout Duration `yaml:"timeout"` 25 26 // NotFollowRedirect specifies the policy for handling redirects. 27 // Default (zero value) is std http package default policy (stop after 10 consecutive requests). 28 NotFollowRedirect bool `yaml:"not_follow_redirects"` 29 30 // ProxyURL specifies the URL of the proxy to use. An empty string means use the environment variables 31 // HTTP_PROXY, HTTPS_PROXY and NO_PROXY (or the lowercase versions thereof) to get the URL. 32 ProxyURL string `yaml:"proxy_url"` 33 34 // TLSConfig specifies the TLS configuration. 35 tlscfg.TLSConfig `yaml:",inline"` 36 } 37 38 // NewHTTPClient returns a new *http.Client given a Client configuration and an error if any. 39 func NewHTTPClient(cfg Client) (*http.Client, error) { 40 tlsConfig, err := tlscfg.NewTLSConfig(cfg.TLSConfig) 41 if err != nil { 42 return nil, fmt.Errorf("error on creating TLS config: %v", err) 43 } 44 45 if cfg.ProxyURL != "" { 46 if _, err := url.Parse(cfg.ProxyURL); err != nil { 47 return nil, fmt.Errorf("error on parsing proxy URL '%s': %v", cfg.ProxyURL, err) 48 } 49 } 50 51 d := &net.Dialer{Timeout: cfg.Timeout.Duration} 52 53 transport := &http.Transport{ 54 Proxy: proxyFunc(cfg.ProxyURL), 55 TLSClientConfig: tlsConfig, 56 DialContext: d.DialContext, 57 TLSHandshakeTimeout: cfg.Timeout.Duration, 58 } 59 60 return &http.Client{ 61 Timeout: cfg.Timeout.Duration, 62 Transport: transport, 63 CheckRedirect: redirectFunc(cfg.NotFollowRedirect), 64 }, nil 65 } 66 67 func redirectFunc(notFollowRedirect bool) func(req *http.Request, via []*http.Request) error { 68 if follow := !notFollowRedirect; follow { 69 return nil 70 } 71 return func(_ *http.Request, _ []*http.Request) error { return ErrRedirectAttempted } 72 } 73 74 func proxyFunc(rawProxyURL string) func(r *http.Request) (*url.URL, error) { 75 if rawProxyURL == "" { 76 return http.ProxyFromEnvironment 77 } 78 proxyURL, _ := url.Parse(rawProxyURL) 79 return http.ProxyURL(proxyURL) 80 }