@@ -31,6 +31,7 @@ import (
31
31
"time"
32
32
33
33
"github.com/mwitkow/go-conntrack"
34
+ "golang.org/x/net/http/httpproxy"
34
35
"golang.org/x/net/http2"
35
36
"golang.org/x/oauth2"
36
37
"golang.org/x/oauth2/clientcredentials"
@@ -227,11 +228,26 @@ type OAuth2 struct {
227
228
Scopes []string `yaml:"scopes,omitempty" json:"scopes,omitempty"`
228
229
TokenURL string `yaml:"token_url" json:"token_url"`
229
230
EndpointParams map [string ]string `yaml:"endpoint_params,omitempty" json:"endpoint_params,omitempty"`
231
+ TLSConfig TLSConfig `yaml:"tls_config,omitempty"`
232
+ ProxyConfig `yaml:",inline"`
233
+ }
230
234
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 ()
235
251
}
236
252
237
253
// SetDirectory joins any relative file paths with dir.
@@ -281,13 +297,6 @@ type HTTPClientConfig struct {
281
297
// The bearer token file for the targets. Deprecated in favour of
282
298
// Authorization.CredentialsFile.
283
299
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"`
291
300
// TLSConfig to use to connect to the targets.
292
301
TLSConfig TLSConfig `yaml:"tls_config,omitempty" json:"tls_config,omitempty"`
293
302
// FollowRedirects specifies whether the client should follow HTTP 3xx redirects.
@@ -298,6 +307,8 @@ type HTTPClientConfig struct {
298
307
// The omitempty flag is not set, because it would be hidden from the
299
308
// marshalled configuration when set to false.
300
309
EnableHTTP2 bool `yaml:"enable_http2" json:"enable_http2"`
310
+ // Proxy configuration.
311
+ ProxyConfig `yaml:",inline"`
301
312
}
302
313
303
314
// SetDirectory joins any relative file paths with dir.
@@ -372,8 +383,8 @@ func (c *HTTPClientConfig) Validate() error {
372
383
return fmt .Errorf ("at most one of oauth2 client_secret & client_secret_file must be configured" )
373
384
}
374
385
}
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
377
388
}
378
389
return nil
379
390
}
@@ -502,8 +513,8 @@ func NewRoundTripperFromConfig(cfg HTTPClientConfig, name string, optFuncs ...HT
502
513
// The only timeout we care about is the configured scrape timeout.
503
514
// It is applied on request. So we leave out any timings here.
504
515
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 (),
507
518
MaxIdleConns : 20000 ,
508
519
MaxIdleConnsPerHost : 1000 , // see https://github.com/golang/go/issues/13801
509
520
DisableKeepAlives : ! opts .keepAlivesEnabled ,
@@ -724,7 +735,8 @@ func (rt *oauth2RoundTripper) RoundTrip(req *http.Request) (*http.Response, erro
724
735
tlsTransport := func (tlsConfig * tls.Config ) (http.RoundTripper , error ) {
725
736
return & http.Transport {
726
737
TLSClientConfig : tlsConfig ,
727
- Proxy : http .ProxyURL (rt .config .ProxyURL .URL ),
738
+ Proxy : rt .config .ProxyConfig .Proxy (),
739
+ ProxyConnectHeader : rt .config .ProxyConfig .GetProxyConnectHeader (),
728
740
DisableKeepAlives : ! rt .opts .keepAlivesEnabled ,
729
741
MaxIdleConns : 20 ,
730
742
MaxIdleConnsPerHost : 1 , // see https://github.com/golang/go/issues/13801
@@ -1072,3 +1084,78 @@ func (c HTTPClientConfig) String() string {
1072
1084
}
1073
1085
return string (b )
1074
1086
}
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