github.com/rclone/rclone@v1.66.1-0.20240517100346-7b89735ae726/backend/putio/error.go (about)

     1  package putio
     2  
     3  import (
     4  	"context"
     5  	"fmt"
     6  	"net/http"
     7  	"strconv"
     8  	"time"
     9  
    10  	"github.com/putdotio/go-putio/putio"
    11  	"github.com/rclone/rclone/fs/fserrors"
    12  	"github.com/rclone/rclone/lib/pacer"
    13  )
    14  
    15  func checkStatusCode(resp *http.Response, expected ...int) error {
    16  	for _, code := range expected {
    17  		if resp.StatusCode == code {
    18  			return nil
    19  		}
    20  	}
    21  	return &statusCodeError{response: resp}
    22  }
    23  
    24  type statusCodeError struct {
    25  	response *http.Response
    26  }
    27  
    28  func (e *statusCodeError) Error() string {
    29  	return fmt.Sprintf("unexpected status code (%d) response while doing %s to %s", e.response.StatusCode, e.response.Request.Method, e.response.Request.URL.String())
    30  }
    31  
    32  // This method is called from fserrors.ShouldRetry() to determine if an error should be retried.
    33  // Some errors (e.g. 429 Too Many Requests) are handled before this step, so they are not included here.
    34  func (e *statusCodeError) Temporary() bool {
    35  	return e.response.StatusCode >= 500
    36  }
    37  
    38  // shouldRetry returns a boolean as to whether this err deserves to be
    39  // retried.  It returns the err as a convenience
    40  func shouldRetry(ctx context.Context, err error) (bool, error) {
    41  	if fserrors.ContextError(ctx, &err) {
    42  		return false, err
    43  	}
    44  	if err == nil {
    45  		return false, nil
    46  	}
    47  	if perr, ok := err.(*putio.ErrorResponse); ok {
    48  		err = &statusCodeError{response: perr.Response}
    49  	}
    50  	if scerr, ok := err.(*statusCodeError); ok && scerr.response.StatusCode == 429 {
    51  		delay := defaultRateLimitSleep
    52  		header := scerr.response.Header.Get("x-ratelimit-reset")
    53  		if header != "" {
    54  			if resetTime, cerr := strconv.ParseInt(header, 10, 64); cerr == nil {
    55  				delay = time.Until(time.Unix(resetTime+1, 0))
    56  			}
    57  		}
    58  		return true, pacer.RetryAfterError(scerr, delay)
    59  	}
    60  	if fserrors.ShouldRetry(err) {
    61  		return true, err
    62  	}
    63  	return false, err
    64  }