func (c Client) executeMethod(ctx context.Context, method string, metadata requestMetadata) (res *http.Response, err error) {
	var isRetryable bool      
	var bodySeeker io.Seeker  
	var reqRetry = MaxRetry   
	defer func() {
		if err != nil {
			c.httpClient.CloseIdleConnections()
		}
	}()
	if metadata.contentBody != nil {
		bodySeeker, isRetryable = metadata.contentBody.(io.Seeker)
		switch bodySeeker {
		case os.Stdin, os.Stdout, os.Stderr:
			isRetryable = false
		}
		if !isRetryable {
			reqRetry = 1
		}
		bodyCloser, ok := metadata.contentBody.(io.Closer)
		if ok {
			defer bodyCloser.Close()
		}
	}
	retryCtx, cancel := context.WithCancel(ctx)
	defer cancel()
	for range c.newRetryTimer(retryCtx, reqRetry, DefaultRetryUnit, DefaultRetryCap, MaxJitter) {
		if isRetryable {
			if _, err = bodySeeker.Seek(0, 0); err != nil {
				return nil, err
			}
		}
		var req *http.Request
		req, err = c.newRequest(method, metadata)
		if err != nil {
			errResponse := ToErrorResponse(err)
			if isS3CodeRetryable(errResponse.Code) {
				continue  
			}
			return nil, err
		}
		req = req.WithContext(ctx)
		res, err = c.do(req)
		if err != nil {
			if err == context.Canceled || err == context.DeadlineExceeded {
				return nil, err
			}
			continue
		}
		for _, httpStatus := range successStatus {
			if httpStatus == res.StatusCode {
				return res, nil
			}
		}
		errBodyBytes, err := ioutil.ReadAll(res.Body)
		closeResponse(res)
		if err != nil {
			return nil, err
		}
		errBodySeeker := bytes.NewReader(errBodyBytes)
		res.Body = ioutil.NopCloser(errBodySeeker)
		errResponse := ToErrorResponse(httpRespToErrorResponse(res, metadata.bucketName, metadata.objectName))
		errBodySeeker.Seek(0, 0)  
		res.Body = ioutil.NopCloser(errBodySeeker)
		if c.region == "" {
			switch errResponse.Code {
			case "AuthorizationHeaderMalformed":
				fallthrough
			case "InvalidRegion":
				fallthrough
			case "AccessDenied":
				if errResponse.Region == "" {
					return res, err
				}
				if metadata.bucketName != "" {
					if location, cachedOk := c.bucketLocCache.Get(metadata.bucketName); cachedOk && location != errResponse.Region {
						c.bucketLocCache.Set(metadata.bucketName, errResponse.Region)
						continue  
					}
				} else {
					if errResponse.Region != metadata.bucketLocation {
						metadata.bucketLocation = errResponse.Region
						continue  
					}
				}
			}
		}
		if isS3CodeRetryable(errResponse.Code) {
			continue  
		}
		if isHTTPStatusRetryable(res.StatusCode) {
			continue  
		}
		break
	}
	if e := retryCtx.Err(); e != nil {
		return nil, e
	}
	return res, err
}
executeMethod - instantiates a given method, and retries the
request upon any error up to maxRetries attempts in a binomially
delayed manner using a standard back off algorithm.
package minio
import (
	"bytes"
	"context"
	"errors"
	"fmt"
	"io"
	"io/ioutil"
	"math/rand"
	"net"
	"net/http"
	"net/http/cookiejar"
	"net/http/httputil"
	"net/url"
	"os"
	"runtime"
	"strings"
	"sync"
	"time"
	md5simd "github.com/minio/md5-simd"
	"github.com/minio/minio-go/v6/pkg/credentials"
	"github.com/minio/minio-go/v6/pkg/s3utils"
	"github.com/minio/minio-go/v6/pkg/signer"
	"golang.org/x/net/publicsuffix"
)
type Client struct {
	endpointURL *url.URL
	credsProvider *credentials.Credentials
	overrideSignerType credentials.SignatureType
	appInfo struct {
		appName    string
		appVersion string
	}
	secure bool
	httpClient     *http.Client
	bucketLocCache *bucketLocationCache
	isTraceEnabled  bool
	traceErrorsOnly bool
	traceOutput     io.Writer
	s3AccelerateEndpoint string
	region string
	random *rand.Rand
	lookup BucketLookupType
	md5Hasher    func() md5simd.Hasher
	sha256Hasher func() md5simd.Hasher
}
type Options struct {
	Creds        *credentials.Credentials
	Secure       bool
	Region       string
	BucketLookup BucketLookupType
	CustomMD5    func() md5simd.Hasher
	CustomSHA256 func() md5simd.Hasher
}
const (
	libraryName    = "minio-go"
	libraryVersion = "v6.0.57"
)
const (
	libraryUserAgentPrefix = "MinIO (" + runtime.GOOS + "; " + runtime.GOARCH + ") "
	libraryUserAgent       = libraryUserAgentPrefix + libraryName + "/" + libraryVersion
)
type BucketLookupType int
const (
	BucketLookupAuto BucketLookupType = iota
	BucketLookupDNS
	BucketLookupPath
)
func NewV2(endpoint string, accessKeyID, secretAccessKey string, secure bool) (*Client, error) {
	clnt, err := privateNew(endpoint, Options{
		Creds:        credentials.NewStaticV2(accessKeyID, secretAccessKey, ""),
		Secure:       secure,
		BucketLookup: BucketLookupAuto,
	})
	if err != nil {
		return nil, err
	}
	clnt.overrideSignerType = credentials.SignatureV2
	return clnt, nil
}
func NewV4(endpoint string, accessKeyID, secretAccessKey string, secure bool) (*Client, error) {
	clnt, err := privateNew(endpoint, Options{
		Creds:        credentials.NewStaticV4(accessKeyID, secretAccessKey, ""),
		Secure:       secure,
		BucketLookup: BucketLookupAuto,
	})
	if err != nil {
		return nil, err
	}
	clnt.overrideSignerType = credentials.SignatureV4
	return clnt, nil
}
func New(endpoint, accessKeyID, secretAccessKey string, secure bool) (*Client, error) {
	clnt, err := privateNew(endpoint, Options{
		Creds:        credentials.NewStaticV4(accessKeyID, secretAccessKey, ""),
		Secure:       secure,
		BucketLookup: BucketLookupAuto,
	})
	if err != nil {
		return nil, err
	}
	if s3utils.IsGoogleEndpoint(*clnt.endpointURL) {
		clnt.overrideSignerType = credentials.SignatureV2
	}
	if s3utils.IsAmazonEndpoint(*clnt.endpointURL) {
		clnt.overrideSignerType = credentials.SignatureV4
	}
	return clnt, nil
}
func NewWithCredentials(endpoint string, creds *credentials.Credentials, secure bool, region string) (*Client, error) {
	return privateNew(endpoint, Options{
		Creds:        creds,
		Secure:       secure,
		BucketLookup: BucketLookupAuto,
		Region:       region,
	})
}
func NewWithRegion(endpoint, accessKeyID, secretAccessKey string, secure bool, region string) (*Client, error) {
	creds := credentials.NewStaticV4(accessKeyID, secretAccessKey, "")
	return privateNew(endpoint, Options{
		Creds:        creds,
		Secure:       secure,
		Region:       region,
		BucketLookup: BucketLookupAuto,
	})
}
func NewWithOptions(endpoint string, opts *Options) (*Client, error) {
	if opts == nil {
		return nil, errors.New("no options provided")
	}
	return privateNew(endpoint, *opts)
}
func (c *Client) EndpointURL() *url.URL {
	endpoint := *c.endpointURL  
	return &endpoint
}
type lockedRandSource struct {
	lk  sync.Mutex
	src rand.Source
}
func (r *lockedRandSource) Int63() (n int64) {
	r.lk.Lock()
	n = r.src.Int63()
	r.lk.Unlock()
	return
}
func (r *lockedRandSource) Seed(seed int64) {
	r.lk.Lock()
	r.src.Seed(seed)
	r.lk.Unlock()
}
func (c *Client) redirectHeaders(req *http.Request, via []*http.Request) error {
	if len(via) >= 5 {
		return errors.New("stopped after 5 redirects")
	}
	if len(via) == 0 {
		return nil
	}
	lastRequest := via[len(via)-1]
	var reAuth bool
	for attr, val := range lastRequest.Header {
		if attr == "Authorization" && req.Host != lastRequest.Host {
			reAuth = true
			continue
		}
		if _, ok := req.Header[attr]; !ok {
			req.Header[attr] = val
		}
	}
	*c.endpointURL = *req.URL
	value, err := c.credsProvider.Get()
	if err != nil {
		return err
	}
	var (
		signerType      = value.SignerType
		accessKeyID     = value.AccessKeyID
		secretAccessKey = value.SecretAccessKey
		sessionToken    = value.SessionToken
		region          = c.region
	)
	if c.overrideSignerType != credentials.SignatureDefault {
		signerType = c.overrideSignerType
	}
	if value.SignerType == credentials.SignatureAnonymous {
		signerType = credentials.SignatureAnonymous
	}
	if reAuth {
		if region == "" {
			region = s3utils.GetRegionFromURL(*c.endpointURL)
		}
		switch {
		case signerType.IsV2():
			return errors.New("signature V2 cannot support redirection")
		case signerType.IsV4():
			signer.SignV4(*req, accessKeyID, secretAccessKey, sessionToken, getDefaultLocation(*c.endpointURL, region))
		}
	}
	return nil
}
func privateNew(endpoint string, opts Options) (*Client, error) {
	endpointURL, err := getEndpointURL(endpoint, opts.Secure)
	if err != nil {
		return nil, err
	}
	jar, err := cookiejar.New(&cookiejar.Options{PublicSuffixList: publicsuffix.List})
	if err != nil {
		return nil, err
	}
	clnt := new(Client)
	clnt.credsProvider = opts.Creds
	clnt.secure = opts.Secure
	clnt.endpointURL = endpointURL
	transport, err := DefaultTransport(opts.Secure)
	if err != nil {
		return nil, err
	}
	clnt.httpClient = &http.Client{
		Jar:           jar,
		Transport:     transport,
		CheckRedirect: clnt.redirectHeaders,
	}
	if opts.Region == "" {
		opts.Region = s3utils.GetRegionFromURL(*clnt.endpointURL)
	}
	clnt.region = opts.Region
	clnt.bucketLocCache = newBucketLocationCache()
	clnt.random = rand.New(&lockedRandSource{src: rand.NewSource(time.Now().UTC().UnixNano())})
	clnt.md5Hasher = opts.CustomMD5
	clnt.sha256Hasher = opts.CustomSHA256
	if clnt.md5Hasher == nil {
		clnt.md5Hasher = newMd5Hasher
	}
	if clnt.sha256Hasher == nil {
		clnt.sha256Hasher = newSHA256Hasher
	}
	clnt.lookup = opts.BucketLookup
	return clnt, nil
}
func (c *Client) SetAppInfo(appName string, appVersion string) {
	if appName != "" && appVersion != "" {
		c.appInfo.appName = appName
		c.appInfo.appVersion = appVersion
	}
}
func (c *Client) SetCustomTransport(customHTTPTransport http.RoundTripper) {
	if c.httpClient != nil {
		c.httpClient.Transport = customHTTPTransport
	}
}
func (c *Client) TraceOn(outputStream io.Writer) {
	if outputStream == nil {
		outputStream = os.Stdout
	}
	c.traceOutput = outputStream
	c.isTraceEnabled = true
}
func (c *Client) TraceErrorsOnlyOn(outputStream io.Writer) {
	c.TraceOn(outputStream)
	c.traceErrorsOnly = true
}
func (c *Client) TraceErrorsOnlyOff() {
	c.traceErrorsOnly = false
}
func (c *Client) TraceOff() {
	c.isTraceEnabled = false
	c.traceErrorsOnly = false
}
func (c *Client) SetS3TransferAccelerate(accelerateEndpoint string) {
	if s3utils.IsAmazonEndpoint(*c.endpointURL) {
		c.s3AccelerateEndpoint = accelerateEndpoint
	}
}
func (c *Client) hashMaterials(isMd5Requested bool) (hashAlgos map[string]md5simd.Hasher, hashSums map[string][]byte) {
	hashSums = make(map[string][]byte)
	hashAlgos = make(map[string]md5simd.Hasher)
	if c.overrideSignerType.IsV4() {
		if c.secure {
			hashAlgos["md5"] = c.md5Hasher()
		} else {
			hashAlgos["sha256"] = c.sha256Hasher()
		}
	} else {
		if c.overrideSignerType.IsAnonymous() {
			hashAlgos["md5"] = c.md5Hasher()
		}
	}
	if isMd5Requested {
		hashAlgos["md5"] = c.md5Hasher()
	}
	return hashAlgos, hashSums
}
type requestMetadata struct {
	presignURL bool
	bucketName   string
	objectName   string
	queryValues  url.Values
	customHeader http.Header
	expires      int64
	bucketLocation   string
	contentBody      io.Reader
	contentLength    int64
	contentMD5Base64 string  
	contentSHA256Hex string  
}
func (c Client) dumpHTTP(req *http.Request, resp *http.Response) error {
	_, err := fmt.Fprintln(c.traceOutput, "---------START-HTTP---------")
	if err != nil {
		return err
	}
	origAuth := req.Header.Get("Authorization")
	if origAuth != "" {
		req.Header.Set("Authorization", redactSignature(origAuth))
	}
	reqTrace, err := httputil.DumpRequestOut(req, false)
	if err != nil {
		return err
	}
	_, err = fmt.Fprint(c.traceOutput, string(reqTrace))
	if err != nil {
		return err
	}
	var respTrace []byte
	if resp.StatusCode != http.StatusOK &&
		resp.StatusCode != http.StatusPartialContent &&
		resp.StatusCode != http.StatusNoContent {
		respTrace, err = httputil.DumpResponse(resp, true)
		if err != nil {
			return err
		}
	} else {
		respTrace, err = httputil.DumpResponse(resp, false)
		if err != nil {
			return err
		}
	}
	_, err = fmt.Fprint(c.traceOutput, strings.TrimSuffix(string(respTrace), "\r\n"))
	if err != nil {
		return err
	}
	_, err = fmt.Fprintln(c.traceOutput, "---------END-HTTP---------")
	if err != nil {
		return err
	}
	return nil
}
func (c Client) do(req *http.Request) (*http.Response, error) {
	resp, err := c.httpClient.Do(req)
	if err != nil {
		if urlErr, ok := err.(*url.Error); ok {
			if strings.Contains(urlErr.Err.Error(), "EOF") {
				return nil, &url.Error{
					Op:  urlErr.Op,
					URL: urlErr.URL,
					Err: errors.New("Connection closed by foreign host " + urlErr.URL + ". Retry again."),
				}
			}
		}
		return nil, err
	}
	if resp == nil {
		msg := "Response is empty. " + reportIssue
		return nil, ErrInvalidArgument(msg)
	}
	if c.isTraceEnabled && !(c.traceErrorsOnly && resp.StatusCode == http.StatusOK) {
		err = c.dumpHTTP(req, resp)
		if err != nil {
			return nil, err
		}
	}
	return resp, nil
}
var successStatus = []int{
	http.StatusOK,
	http.StatusNoContent,
	http.StatusPartialContent,
}