diff --git a/config/http_config.go b/config/http_config.go index 07b389eb..af9e463b 100644 --- a/config/http_config.go +++ b/config/http_config.go @@ -33,6 +33,11 @@ import ( "gopkg.in/yaml.v2" ) +// DefaultHTTPClientConfig is the default HTTP client configuration. +var DefaultHTTPClientConfig = HTTPClientConfig{ + FollowRedirects: true, +} + type closeIdler interface { CloseIdleConnections() } @@ -111,6 +116,10 @@ type HTTPClientConfig struct { ProxyURL URL `yaml:"proxy_url,omitempty"` // TLSConfig to use to connect to the targets. TLSConfig TLSConfig `yaml:"tls_config,omitempty"` + // FollowRedirects specifies whether the client should follow HTTP 3xx redirects. + // The omitempty flag is not set, because it would be hidden from the + // marshalled configuration when set to false. + FollowRedirects bool `yaml:"follow_redirects"` } // SetDirectory joins any relative file paths with dir. @@ -172,6 +181,7 @@ func (c *HTTPClientConfig) Validate() error { // UnmarshalYAML implements the yaml.Unmarshaler interface func (c *HTTPClientConfig) UnmarshalYAML(unmarshal func(interface{}) error) error { type plain HTTPClientConfig + *c = DefaultHTTPClientConfig if err := unmarshal((*plain)(c)); err != nil { return err } @@ -196,7 +206,13 @@ func NewClientFromConfig(cfg HTTPClientConfig, name string, disableKeepAlives, e if err != nil { return nil, err } - return newClient(rt), nil + client := newClient(rt) + if !cfg.FollowRedirects { + client.CheckRedirect = func(*http.Request, []*http.Request) error { + return http.ErrUseLastResponse + } + } + return client, nil } // NewRoundTripperFromConfig returns a new HTTP RoundTripper configured for the diff --git a/config/http_config_test.go b/config/http_config_test.go index a35ae895..c96560e4 100644 --- a/config/http_config_test.go +++ b/config/http_config_test.go @@ -296,6 +296,46 @@ func TestNewClientFromConfig(t *testing.T) { fmt.Fprint(w, ExpectedMessage) } }, + }, { + clientConfig: HTTPClientConfig{ + FollowRedirects: true, + TLSConfig: TLSConfig{ + CAFile: TLSCAChainPath, + CertFile: ClientCertificatePath, + KeyFile: ClientKeyNoPassPath, + ServerName: "", + InsecureSkipVerify: false}, + }, + handler: func(w http.ResponseWriter, r *http.Request) { + switch r.URL.Path { + case "/redirected": + fmt.Fprintf(w, ExpectedMessage) + default: + w.Header().Set("Location", "/redirected") + w.WriteHeader(http.StatusFound) + fmt.Fprintf(w, "It should follow the redirect.") + } + }, + }, { + clientConfig: HTTPClientConfig{ + FollowRedirects: false, + TLSConfig: TLSConfig{ + CAFile: TLSCAChainPath, + CertFile: ClientCertificatePath, + KeyFile: ClientKeyNoPassPath, + ServerName: "", + InsecureSkipVerify: false}, + }, + handler: func(w http.ResponseWriter, r *http.Request) { + switch r.URL.Path { + case "/redirected": + fmt.Fprint(w, "The redirection was followed.") + default: + w.Header().Set("Location", "/redirected") + w.WriteHeader(http.StatusFound) + fmt.Fprintf(w, ExpectedMessage) + } + }, }, } @@ -317,7 +357,7 @@ func TestNewClientFromConfig(t *testing.T) { } response, err := client.Get(testServer.URL) if err != nil { - t.Errorf("Can't connect to the test server using this config: %+v", validConfig.clientConfig) + t.Errorf("Can't connect to the test server using this config: %+v: %v", validConfig.clientConfig, err) continue } @@ -932,6 +972,16 @@ func TestHideHTTPClientConfigSecrets(t *testing.T) { } } +func TestDefaultFollowRedirect(t *testing.T) { + cfg, _, err := LoadHTTPConfigFile("testdata/http.conf.good.yml") + if err != nil { + t.Errorf("Error loading HTTP client config: %v", err) + } + if !cfg.FollowRedirects { + t.Errorf("follow_redirects should be true") + } +} + func TestValidateHTTPConfig(t *testing.T) { cfg, _, err := LoadHTTPConfigFile("testdata/http.conf.good.yml") if err != nil {