diff options
Diffstat (limited to 'vendor/github.com/minio/minio-go/v7/api.go')
-rw-r--r-- | vendor/github.com/minio/minio-go/v7/api.go | 111 |
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) } } } |