@@ -31,6 +31,7 @@ import (
3131 "time"
3232
3333 "github.com/mwitkow/go-conntrack"
34+ "golang.org/x/net/http/httpproxy"
3435 "golang.org/x/net/http2"
3536 "golang.org/x/oauth2"
3637 "golang.org/x/oauth2/clientcredentials"
@@ -227,11 +228,26 @@ type OAuth2 struct {
227228 Scopes []string `yaml:"scopes,omitempty" json:"scopes,omitempty"`
228229 TokenURL string `yaml:"token_url" json:"token_url"`
229230 EndpointParams map [string ]string `yaml:"endpoint_params,omitempty" json:"endpoint_params,omitempty"`
231+ TLSConfig TLSConfig `yaml:"tls_config,omitempty"`
232+ ProxyConfig `yaml:",inline"`
233+ }
230234
231- // HTTP proxy server to use to connect to the targets.
232- ProxyURL URL `yaml:"proxy_url,omitempty" json:"proxy_url,omitempty"`
233- // TLSConfig is used to connect to the token URL.
234- TLSConfig TLSConfig `yaml:"tls_config,omitempty"`
235+ // UnmarshalYAML implements the yaml.Unmarshaler interface
236+ func (o * OAuth2 ) UnmarshalYAML (unmarshal func (interface {}) error ) error {
237+ type plain OAuth2
238+ if err := unmarshal ((* plain )(o )); err != nil {
239+ return err
240+ }
241+ return o .ProxyConfig .Validate ()
242+ }
243+
244+ // UnmarshalJSON implements the json.Marshaler interface for URL.
245+ func (o * OAuth2 ) UnmarshalJSON (data []byte ) error {
246+ type plain OAuth2
247+ if err := json .Unmarshal (data , (* plain )(o )); err != nil {
248+ return err
249+ }
250+ return o .ProxyConfig .Validate ()
235251}
236252
237253// SetDirectory joins any relative file paths with dir.
@@ -281,13 +297,6 @@ type HTTPClientConfig struct {
281297 // The bearer token file for the targets. Deprecated in favour of
282298 // Authorization.CredentialsFile.
283299 BearerTokenFile string `yaml:"bearer_token_file,omitempty" json:"bearer_token_file,omitempty"`
284- // HTTP proxy server to use to connect to the targets.
285- ProxyURL URL `yaml:"proxy_url,omitempty" json:"proxy_url,omitempty"`
286- // ProxyConnectHeader optionally specifies headers to send to
287- // proxies during CONNECT requests. Assume that at least _some_ of
288- // these headers are going to contain secrets and use Secret as the
289- // value type instead of string.
290- ProxyConnectHeader Header `yaml:"proxy_connect_header,omitempty" json:"proxy_connect_header,omitempty"`
291300 // TLSConfig to use to connect to the targets.
292301 TLSConfig TLSConfig `yaml:"tls_config,omitempty" json:"tls_config,omitempty"`
293302 // FollowRedirects specifies whether the client should follow HTTP 3xx redirects.
@@ -298,6 +307,8 @@ type HTTPClientConfig struct {
298307 // The omitempty flag is not set, because it would be hidden from the
299308 // marshalled configuration when set to false.
300309 EnableHTTP2 bool `yaml:"enable_http2" json:"enable_http2"`
310+ // Proxy configuration.
311+ ProxyConfig `yaml:",inline"`
301312}
302313
303314// SetDirectory joins any relative file paths with dir.
@@ -372,8 +383,8 @@ func (c *HTTPClientConfig) Validate() error {
372383 return fmt .Errorf ("at most one of oauth2 client_secret & client_secret_file must be configured" )
373384 }
374385 }
375- if len ( c . ProxyConnectHeader ) > 0 && ( c . ProxyURL . URL == nil || c . ProxyURL . String () == "" ) {
376- return fmt . Errorf ( "if proxy_connect_header is configured proxy_url must also be configured" )
386+ if err := c . ProxyConfig . Validate (); err != nil {
387+ return err
377388 }
378389 return nil
379390}
@@ -502,8 +513,8 @@ func NewRoundTripperFromConfig(cfg HTTPClientConfig, name string, optFuncs ...HT
502513 // The only timeout we care about is the configured scrape timeout.
503514 // It is applied on request. So we leave out any timings here.
504515 var rt http.RoundTripper = & http.Transport {
505- Proxy : http . ProxyURL ( cfg .ProxyURL . URL ),
506- ProxyConnectHeader : cfg .ProxyConnectHeader . HTTPHeader (),
516+ Proxy : cfg .ProxyConfig . Proxy ( ),
517+ ProxyConnectHeader : cfg .ProxyConfig . GetProxyConnectHeader (),
507518 MaxIdleConns : 20000 ,
508519 MaxIdleConnsPerHost : 1000 , // see https://github.com/golang/go/issues/13801
509520 DisableKeepAlives : ! opts .keepAlivesEnabled ,
@@ -724,7 +735,8 @@ func (rt *oauth2RoundTripper) RoundTrip(req *http.Request) (*http.Response, erro
724735 tlsTransport := func (tlsConfig * tls.Config ) (http.RoundTripper , error ) {
725736 return & http.Transport {
726737 TLSClientConfig : tlsConfig ,
727- Proxy : http .ProxyURL (rt .config .ProxyURL .URL ),
738+ Proxy : rt .config .ProxyConfig .Proxy (),
739+ ProxyConnectHeader : rt .config .ProxyConfig .GetProxyConnectHeader (),
728740 DisableKeepAlives : ! rt .opts .keepAlivesEnabled ,
729741 MaxIdleConns : 20 ,
730742 MaxIdleConnsPerHost : 1 , // see https://github.com/golang/go/issues/13801
@@ -1072,3 +1084,78 @@ func (c HTTPClientConfig) String() string {
10721084 }
10731085 return string (b )
10741086}
1087+
1088+ type ProxyConfig struct {
1089+ // HTTP proxy server to use to connect to the targets.
1090+ ProxyURL URL `yaml:"proxy_url,omitempty" json:"proxy_url,omitempty"`
1091+ // NoProxy contains addresses that should not use a proxy.
1092+ NoProxy string `yaml:"no_proxy,omitempty" json:"no_proxy,omitempty"`
1093+ // ProxyFromEnvironment makes use of net/http ProxyFromEnvironment function
1094+ // to determine proxies.
1095+ ProxyFromEnvironment bool `yaml:"proxy_from_environment,omitempty" json:"proxy_from_environment,omitempty"`
1096+ // ProxyConnectHeader optionally specifies headers to send to
1097+ // proxies during CONNECT requests. Assume that at least _some_ of
1098+ // these headers are going to contain secrets and use Secret as the
1099+ // value type instead of string.
1100+ ProxyConnectHeader Header `yaml:"proxy_connect_header,omitempty" json:"proxy_connect_header,omitempty"`
1101+
1102+ proxyFunc func (* http.Request ) (* url.URL , error )
1103+ }
1104+
1105+ // UnmarshalYAML implements the yaml.Unmarshaler interface.
1106+ func (c * ProxyConfig ) Validate () error {
1107+ if len (c .ProxyConnectHeader ) > 0 && (! c .ProxyFromEnvironment && (c .ProxyURL .URL == nil || c .ProxyURL .String () == "" )) {
1108+ return fmt .Errorf ("if proxy_connect_header is configured, proxy_url or proxy_from_environment must also be configured" )
1109+ }
1110+ if c .ProxyFromEnvironment && c .ProxyURL .URL != nil && c .ProxyURL .String () != "" {
1111+ return fmt .Errorf ("if proxy_from_environment is configured, proxy_url must not be configured" )
1112+ }
1113+ if c .ProxyFromEnvironment && c .NoProxy != "" {
1114+ return fmt .Errorf ("if proxy_from_environment is configured, no_proxy must not be configured" )
1115+ }
1116+ if c .ProxyURL .URL == nil && c .NoProxy != "" {
1117+ return fmt .Errorf ("if no_proxy is configured, proxy_url must also be configured" )
1118+ }
1119+ return nil
1120+ }
1121+
1122+ // Proxy returns the Proxy URL for a request.
1123+ func (c * ProxyConfig ) Proxy () (fn func (* http.Request ) (* url.URL , error )) {
1124+ if c == nil {
1125+ return nil
1126+ }
1127+ defer func () {
1128+ fn = c .proxyFunc
1129+ }()
1130+ if c .proxyFunc != nil {
1131+ return
1132+ }
1133+ if c .ProxyFromEnvironment {
1134+ proxyFn := httpproxy .FromEnvironment ().ProxyFunc ()
1135+ c .proxyFunc = func (req * http.Request ) (* url.URL , error ) {
1136+ return proxyFn (req .URL )
1137+ }
1138+ return
1139+ }
1140+ if c .ProxyURL .URL != nil && c .ProxyURL .URL .String () != "" {
1141+ if c .NoProxy == "" {
1142+ c .proxyFunc = http .ProxyURL (c .ProxyURL .URL )
1143+ return
1144+ }
1145+ proxy := & httpproxy.Config {
1146+ HTTPProxy : c .ProxyURL .String (),
1147+ HTTPSProxy : c .ProxyURL .String (),
1148+ NoProxy : c .NoProxy ,
1149+ }
1150+ proxyFn := proxy .ProxyFunc ()
1151+ c .proxyFunc = func (req * http.Request ) (* url.URL , error ) {
1152+ return proxyFn (req .URL )
1153+ }
1154+ }
1155+ return
1156+ }
1157+
1158+ // ProxyConnectHeader() return the Proxy Connext Headers.
1159+ func (c * ProxyConfig ) GetProxyConnectHeader () http.Header {
1160+ return c .ProxyConnectHeader .HTTPHeader ()
1161+ }
0 commit comments