errors.go 1.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051
  1. // Copyright (c) Tailscale Inc & contributors
  2. // SPDX-License-Identifier: BSD-3-Clause
  3. package controlclient
  4. import (
  5. "errors"
  6. "fmt"
  7. "net/http"
  8. )
  9. // apiResponseError is an error type that can be returned by controlclient
  10. // api requests.
  11. //
  12. // It wraps an underlying error and a flag for clients to query if the
  13. // error is retryable via the Retryable() method.
  14. type apiResponseError struct {
  15. err error
  16. retryable bool
  17. }
  18. // Error implements [error].
  19. func (e *apiResponseError) Error() string {
  20. return e.err.Error()
  21. }
  22. // Retryable reports whether the error is retryable.
  23. func (e *apiResponseError) Retryable() bool {
  24. return e.retryable
  25. }
  26. func (e *apiResponseError) Unwrap() error { return e.err }
  27. var (
  28. errNoNodeKey = &apiResponseError{errors.New("no node key"), true}
  29. errNoNoiseClient = &apiResponseError{errors.New("no noise client"), true}
  30. errHTTPPostFailure = &apiResponseError{errors.New("http failure"), true}
  31. )
  32. func errBadHTTPResponse(code int, msg string) error {
  33. retryable := false
  34. switch code {
  35. case http.StatusTooManyRequests,
  36. http.StatusInternalServerError,
  37. http.StatusBadGateway,
  38. http.StatusServiceUnavailable,
  39. http.StatusGatewayTimeout:
  40. retryable = true
  41. }
  42. return &apiResponseError{fmt.Errorf("http error %d: %s", code, msg), retryable}
  43. }