package client import ( "net/http" "net" "time" "errors" "net/url" "io" ) var ( httpCannotRedirectError = errors.New("this client cannot redirect") disableRedirect = func(_ *http.Request, _ []*http.Request) error { return httpCannotRedirectError } limitedRedirect = func(_ *http.Request, via []*http.Request) error { if len(via) >= 10 { return errors.New("stopped after 10 redirects") } return nil } ) type GracefulClient interface { http.RoundTripper client() *http.Client roundTripper() http.RoundTripper Do(req *http.Request) (*http.Response, error) Get(url string) (resp *http.Response, err error) Head(url string) (resp *http.Response, err error) Post(url string, contentType string, body io.Reader) (resp *http.Response, err error) PostForm(url string, data url.Values) (resp *http.Response, err error) } type wrappedClient struct { http.Client } func (cli *wrappedClient) client() (*http.Client) { return &cli.Client } func (cli *wrappedClient) roundTripper() http.RoundTripper { return cli.Transport } func (cli *wrappedClient) RoundTrip(req *http.Request) (*http.Response, error) { return cli.Client.Transport.RoundTrip(req) } func NewClient( keepaliveDuration time.Duration, connectTimeout time.Duration, responseHeaderTimeout time.Duration, idleConnectionTimeout time.Duration, maxIdleConnections int, redirectSupport bool, serverName string, ) GracefulClient { srvName := []string{serverName} var redirectChecker func(*http.Request, []*http.Request) error if redirectSupport { redirectChecker = limitedRedirect } else { redirectChecker = disableRedirect } keepaliveDisabled := keepaliveDuration == 0 dialer := &net.Dialer{ Timeout: connectTimeout, KeepAlive: keepaliveDuration, DualStack: false, } transport := &predefinedHeaderTransport{ useragentName: srvName, Transport: http.Transport{ Proxy: nil, DialTLS: nil, TLSClientConfig: nil, DisableKeepAlives: keepaliveDisabled, DisableCompression: true, MaxIdleConnsPerHost: maxIdleConnections, DialContext: dialer.DialContext, MaxIdleConns: maxIdleConnections, IdleConnTimeout: idleConnectionTimeout, ResponseHeaderTimeout: responseHeaderTimeout, TLSNextProto: nil, ExpectContinueTimeout: 0, }, } return &wrappedClient{ Client: http.Client{ Transport: transport, CheckRedirect: redirectChecker, Jar: nil, }, } }