1package httpclient
2
3import (
4	"net/http"
5	"time"
6
7	"github.com/cloudfoundry/bosh-utils/errors"
8	boshlog "github.com/cloudfoundry/bosh-utils/logger"
9	boshretry "github.com/cloudfoundry/bosh-utils/retrystrategy"
10)
11
12type retryClient struct {
13	delegate              Client
14	maxAttempts           uint
15	retryDelay            time.Duration
16	logger                boshlog.Logger
17	isResponseAttemptable func(*http.Response, error) (bool, error)
18}
19
20func NewRetryClient(
21	delegate Client,
22	maxAttempts uint,
23	retryDelay time.Duration,
24	logger boshlog.Logger,
25) Client {
26	return &retryClient{
27		delegate:              delegate,
28		maxAttempts:           maxAttempts,
29		retryDelay:            retryDelay,
30		logger:                logger,
31		isResponseAttemptable: nil,
32	}
33}
34
35func NewNetworkSafeRetryClient(
36	delegate Client,
37	maxAttempts uint,
38	retryDelay time.Duration,
39	logger boshlog.Logger,
40) Client {
41	return &retryClient{
42		delegate:    delegate,
43		maxAttempts: maxAttempts,
44		retryDelay:  retryDelay,
45		logger:      logger,
46		isResponseAttemptable: func(resp *http.Response, err error) (bool, error) {
47			if err != nil || ((resp.Request.Method == "GET" || resp.Request.Method == "HEAD") && (resp.StatusCode == http.StatusGatewayTimeout || resp.StatusCode == http.StatusServiceUnavailable || resp.StatusCode == http.StatusBadGateway)) {
48				return true, errors.WrapError(err, "Retry")
49			}
50
51			return false, nil
52		},
53	}
54}
55
56func (r *retryClient) Do(req *http.Request) (*http.Response, error) {
57	requestRetryable := NewRequestRetryable(req, r.delegate, r.logger, r.isResponseAttemptable)
58	retryStrategy := boshretry.NewAttemptRetryStrategy(int(r.maxAttempts), r.retryDelay, requestRetryable, r.logger)
59	err := retryStrategy.Try()
60
61	return requestRetryable.Response(), err
62}
63