summaryrefslogtreecommitdiffstats
path: root/vendor/github.com/minio/minio-go/v7/api.go
diff options
context:
space:
mode:
Diffstat (limited to 'vendor/github.com/minio/minio-go/v7/api.go')
-rw-r--r--vendor/github.com/minio/minio-go/v7/api.go111
1 files changed, 56 insertions, 55 deletions
diff --git a/vendor/github.com/minio/minio-go/v7/api.go b/vendor/github.com/minio/minio-go/v7/api.go
index c8550ef1..b5eaa690 100644
--- a/vendor/github.com/minio/minio-go/v7/api.go
+++ b/vendor/github.com/minio/minio-go/v7/api.go
@@ -46,7 +46,7 @@ import (
// Client implements Amazon S3 compatible methods.
type Client struct {
- /// Standard options.
+ // Standard options.
// Parsed endpoint url provided by the user.
endpointURL *url.URL
@@ -92,9 +92,7 @@ type Client struct {
md5Hasher func() md5simd.Hasher
sha256Hasher func() md5simd.Hasher
- healthCheckCh chan struct{}
- healthCheck int32
- lastOnline time.Time
+ healthStatus int32
}
// Options for New method
@@ -113,7 +111,7 @@ type Options struct {
// Global constants.
const (
libraryName = "minio-go"
- libraryVersion = "v7.0.14"
+ libraryVersion = "v7.0.16"
)
// User Agent should always following the below style.
@@ -312,7 +310,7 @@ func privateNew(endpoint string, opts *Options) (*Client, error) {
clnt.lookup = opts.BucketLookup
// healthcheck is not initialized
- clnt.healthCheck = unknown
+ clnt.healthStatus = unknown
// Return.
return clnt, nil
@@ -404,30 +402,30 @@ const (
// IsOnline returns true if healthcheck enabled and client is online
func (c *Client) IsOnline() bool {
- switch atomic.LoadInt32(&c.healthCheck) {
- case online, unknown:
- return true
- }
- return false
+ return !c.IsOffline()
+}
+
+// sets online healthStatus to offline
+func (c *Client) markOffline() {
+ atomic.CompareAndSwapInt32(&c.healthStatus, online, offline)
}
// IsOffline returns true if healthcheck enabled and client is offline
func (c *Client) IsOffline() bool {
- return !c.IsOnline()
+ return atomic.LoadInt32(&c.healthStatus) == offline
}
// HealthCheck starts a healthcheck to see if endpoint is up. Returns a context cancellation function
// and and error if health check is already started
func (c *Client) HealthCheck(hcDuration time.Duration) (context.CancelFunc, error) {
- if atomic.LoadInt32(&c.healthCheck) == online {
- return nil, fmt.Errorf("health check running already")
+ if atomic.LoadInt32(&c.healthStatus) == online {
+ return nil, fmt.Errorf("health check is running")
}
if hcDuration < 1*time.Second {
return nil, fmt.Errorf("health check duration should be atleast 1 second")
}
ctx, cancelFn := context.WithCancel(context.Background())
- c.healthCheckCh = make(chan struct{})
- atomic.StoreInt32(&c.healthCheck, online)
+ atomic.StoreInt32(&c.healthStatus, online)
probeBucketName := randString(60, rand.NewSource(time.Now().UnixNano()), "probe-health-")
go func(duration time.Duration) {
timer := time.NewTimer(duration)
@@ -435,27 +433,24 @@ func (c *Client) HealthCheck(hcDuration time.Duration) (context.CancelFunc, erro
for {
select {
case <-ctx.Done():
- close(c.healthCheckCh)
- atomic.StoreInt32(&c.healthCheck, unknown)
+ atomic.StoreInt32(&c.healthStatus, unknown)
return
case <-timer.C:
-
timer.Reset(duration)
// Do health check the first time and ONLY if the connection is marked offline
- if c.IsOffline() || c.lastOnline.IsZero() {
- _, err := c.getBucketLocation(context.Background(), probeBucketName)
- if err != nil && IsNetworkOrHostDown(err, false) {
- atomic.StoreInt32(&c.healthCheck, offline)
+ if c.IsOffline() {
+ gctx, gcancel := context.WithTimeout(context.Background(), 3*time.Second)
+ _, err := c.getBucketLocation(gctx, probeBucketName)
+ gcancel()
+ if IsNetworkOrHostDown(err, false) {
+ // Still network errors do not need to do anything.
+ continue
}
switch ToErrorResponse(err).Code {
case "NoSuchBucket", "AccessDenied", "":
- c.lastOnline = time.Now()
- atomic.StoreInt32(&c.healthCheck, online)
+ atomic.CompareAndSwapInt32(&c.healthStatus, offline, online)
}
}
- case <-c.healthCheckCh:
- // set offline if client saw a network error
- atomic.StoreInt32(&c.healthCheck, offline)
}
}
}(hcDuration)
@@ -468,11 +463,12 @@ type requestMetadata struct {
presignURL bool
// User supplied.
- bucketName string
- objectName string
- queryValues url.Values
- customHeader http.Header
- expires int64
+ bucketName string
+ objectName string
+ queryValues url.Values
+ customHeader http.Header
+ extraPresignHeader http.Header
+ expires int64
// Generated by our internal code.
bucketLocation string
@@ -483,7 +479,7 @@ type requestMetadata struct {
}
// dumpHTTP - dump HTTP request and response.
-func (c Client) dumpHTTP(req *http.Request, resp *http.Response) error {
+func (c *Client) dumpHTTP(req *http.Request, resp *http.Response) error {
// Starts http dump.
_, err := fmt.Fprintln(c.traceOutput, "---------START-HTTP---------")
if err != nil {
@@ -543,8 +539,14 @@ func (c Client) dumpHTTP(req *http.Request, resp *http.Response) error {
}
// do - execute http request.
-func (c Client) do(req *http.Request) (*http.Response, error) {
- resp, err := c.httpClient.Do(req)
+func (c *Client) do(req *http.Request) (resp *http.Response, err error) {
+ defer func() {
+ if IsNetworkOrHostDown(err, false) {
+ c.markOffline()
+ }
+ }()
+
+ resp, err = c.httpClient.Do(req)
if err != nil {
// Handle this specifically for now until future Golang versions fix this issue properly.
if urlErr, ok := err.(*url.Error); ok {
@@ -587,7 +589,11 @@ var successStatus = []int{
// 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.
-func (c Client) executeMethod(ctx context.Context, method string, metadata requestMetadata) (res *http.Response, err error) {
+func (c *Client) executeMethod(ctx context.Context, method string, metadata requestMetadata) (res *http.Response, err error) {
+ if c.IsOffline() {
+ return nil, errors.New(c.endpointURL.String() + " is offline.")
+ }
+
var retryable bool // Indicates if request can be retried.
var bodySeeker io.Seeker // Extracted seeker from io.Reader.
var reqRetry = MaxRetry // Indicates how many times we can retry the request
@@ -641,24 +647,11 @@ func (c Client) executeMethod(ctx context.Context, method string, metadata reque
continue // Retry.
}
- if atomic.LoadInt32(&c.healthCheck) != unknown && IsNetworkOrHostDown(err, false) {
- select {
- case c.healthCheckCh <- struct{}{}:
- default:
- }
- }
return nil, err
}
// Initiate the request.
res, err = c.do(req)
if err != nil {
- if atomic.LoadInt32(&c.healthCheck) != unknown && IsNetworkOrHostDown(err, false) {
- select {
- case c.healthCheckCh <- struct{}{}:
- default:
- }
- }
-
if errors.Is(err, context.Canceled) || errors.Is(err, context.DeadlineExceeded) {
return nil, err
}
@@ -753,7 +746,7 @@ func (c Client) executeMethod(ctx context.Context, method string, metadata reque
}
// newRequest - instantiate a new HTTP request for a given method.
-func (c Client) newRequest(ctx context.Context, method string, metadata requestMetadata) (req *http.Request, err error) {
+func (c *Client) newRequest(ctx context.Context, method string, metadata requestMetadata) (req *http.Request, err error) {
// If no method is supplied default to 'POST'.
if method == "" {
method = http.MethodPost
@@ -821,6 +814,14 @@ func (c Client) newRequest(ctx context.Context, method string, metadata requestM
if signerType.IsAnonymous() {
return nil, errInvalidArgument("Presigned URLs cannot be generated with anonymous credentials.")
}
+ if metadata.extraPresignHeader != nil {
+ if signerType.IsV2() {
+ return nil, errInvalidArgument("Extra signed headers for Presign with Signature V2 is not supported.")
+ }
+ for k, v := range metadata.extraPresignHeader {
+ req.Header.Set(k, v[0])
+ }
+ }
if signerType.IsV2() {
// Presign URL with signature v2.
req = signer.PreSignV2(*req, accessKeyID, secretAccessKey, metadata.expires, isVirtualHost)
@@ -893,7 +894,7 @@ func (c Client) newRequest(ctx context.Context, method string, metadata requestM
}
// set User agent.
-func (c Client) setUserAgent(req *http.Request) {
+func (c *Client) setUserAgent(req *http.Request) {
req.Header.Set("User-Agent", libraryUserAgent)
if c.appInfo.appName != "" && c.appInfo.appVersion != "" {
req.Header.Set("User-Agent", libraryUserAgent+" "+c.appInfo.appName+"/"+c.appInfo.appVersion)
@@ -901,7 +902,7 @@ func (c Client) setUserAgent(req *http.Request) {
}
// makeTargetURL make a new target url.
-func (c Client) makeTargetURL(bucketName, objectName, bucketLocation string, isVirtualHostStyle bool, queryValues url.Values) (*url.URL, error) {
+func (c *Client) makeTargetURL(bucketName, objectName, bucketLocation string, isVirtualHostStyle bool, queryValues url.Values) (*url.URL, error) {
host := c.endpointURL.Host
// For Amazon S3 endpoint, try to fetch location based endpoint.
if s3utils.IsAmazonEndpoint(*c.endpointURL) {
@@ -946,13 +947,13 @@ func (c Client) makeTargetURL(bucketName, objectName, bucketLocation string, isV
if isVirtualHostStyle {
urlStr = scheme + "://" + bucketName + "." + host + "/"
if objectName != "" {
- urlStr = urlStr + s3utils.EncodePath(objectName)
+ urlStr += s3utils.EncodePath(objectName)
}
} else {
// If not fall back to using path style.
urlStr = urlStr + bucketName + "/"
if objectName != "" {
- urlStr = urlStr + s3utils.EncodePath(objectName)
+ urlStr += s3utils.EncodePath(objectName)
}
}
}