// shouldRetry returns a boolean as to whether this resp and err // deserve to be retried. It returns the err as a convenience func (f *Fs) shouldRetry(resp *http.Response, err error) (bool, error) { if resp != nil { if resp.StatusCode == 401 { f.ts.Invalidate() fs.Log(f, "401 error received - invalidating token") return true, err } // Work around receiving this error sporadically on authentication // // HTTP code 403: "403 Forbidden", reponse body: {"message":"Authorization header requires 'Credential' parameter. Authorization header requires 'Signature' parameter. Authorization header requires 'SignedHeaders' parameter. Authorization header requires existence of either a 'X-Amz-Date' or a 'Date' header. Authorization=Bearer"} if resp.StatusCode == 403 && strings.Contains(err.Error(), "Authorization header requires") { fs.Log(f, "403 \"Authorization header requires...\" error received - retry") return true, err } } return fs.ShouldRetry(err) || fs.ShouldRetryHTTP(resp, retryErrorCodes), err }
// shouldRetry determines whehter a given err rates being retried func shouldRetry(err error) (again bool, errOut error) { again = false if err != nil { if fs.ShouldRetry(err) { again = true } else { switch gerr := err.(type) { case *googleapi.Error: if gerr.Code >= 500 && gerr.Code < 600 { // All 5xx errors should be retried again = true } else if len(gerr.Errors) > 0 { reason := gerr.Errors[0].Reason if reason == "rateLimitExceeded" || reason == "userRateLimitExceeded" { again = true } } } } } return again, err }
// shouldRetryNoAuth returns a boolean as to whether this resp and err // deserve to be retried. It returns the err as a convenience func (f *Fs) shouldRetryNoReauth(resp *http.Response, err error) (bool, error) { // For 429 or 503 errors look at the Retry-After: header and // set the retry appropriately, starting with a minimum of 1 // second if it isn't set. if resp != nil && (resp.StatusCode == 429 || resp.StatusCode == 503) { var retryAfter = 1 retryAfterString := resp.Header.Get(retryAfterHeader) if retryAfterString != "" { var err error retryAfter, err = strconv.Atoi(retryAfterString) if err != nil { fs.ErrorLog(f, "Malformed %s header %q: %v", retryAfterHeader, retryAfterString, err) } } retryAfterDuration := time.Duration(retryAfter) * time.Second if f.pacer.GetSleep() < retryAfterDuration { fs.Debug(f, "Setting sleep to %v after error: %v", retryAfterDuration, err) // We set 1/2 the value here because the pacer will double it immediately f.pacer.SetSleep(retryAfterDuration / 2) } return true, err } return fs.ShouldRetry(err) || fs.ShouldRetryHTTP(resp, retryErrorCodes), err }
// shouldRetry returns a boolean as to whether this resp and err // deserve to be retried. It returns the err as a convenience func shouldRetry(resp *http.Response, err error) (bool, error) { return fs.ShouldRetry(err) || fs.ShouldRetryHTTP(resp, retryErrorCodes), err }