errors.go 4.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183
  1. package imagedata
  2. import (
  3. "context"
  4. "errors"
  5. "fmt"
  6. "net/http"
  7. "github.com/imgproxy/imgproxy/v3/ierrors"
  8. "github.com/imgproxy/imgproxy/v3/security"
  9. )
  10. type (
  11. ImageRequestError struct{ error }
  12. ImageRequstSchemeError string
  13. ImagePartialResponseError string
  14. ImageResponseStatusError string
  15. ImageTooManyRedirectsError string
  16. ImageRequestCanceledError struct{ error }
  17. ImageRequestTimeoutError struct{ error }
  18. NotModifiedError struct {
  19. headers map[string]string
  20. }
  21. httpError interface {
  22. Timeout() bool
  23. }
  24. )
  25. func newImageRequestError(err error) error {
  26. return ierrors.Wrap(
  27. ImageRequestError{err},
  28. 1,
  29. ierrors.WithStatusCode(http.StatusNotFound),
  30. ierrors.WithPublicMessage(msgSourceImageIsUnreachable),
  31. ierrors.WithShouldReport(false),
  32. )
  33. }
  34. func (e ImageRequestError) Unwrap() error {
  35. return e.error
  36. }
  37. func newImageRequstSchemeError(scheme string) error {
  38. return ierrors.Wrap(
  39. ImageRequstSchemeError(fmt.Sprintf("Unknown scheme: %s", scheme)),
  40. 1,
  41. ierrors.WithStatusCode(http.StatusNotFound),
  42. ierrors.WithPublicMessage(msgSourceImageIsUnreachable),
  43. ierrors.WithShouldReport(false),
  44. )
  45. }
  46. func (e ImageRequstSchemeError) Error() string { return string(e) }
  47. func newImagePartialResponseError(msg string) error {
  48. return ierrors.Wrap(
  49. ImagePartialResponseError(msg),
  50. 1,
  51. ierrors.WithStatusCode(http.StatusNotFound),
  52. ierrors.WithPublicMessage(msgSourceImageIsUnreachable),
  53. ierrors.WithShouldReport(false),
  54. )
  55. }
  56. func (e ImagePartialResponseError) Error() string { return string(e) }
  57. func newImageResponseStatusError(status int, body string) error {
  58. var msg string
  59. if len(body) > 0 {
  60. msg = fmt.Sprintf("Status: %d; %s", status, body)
  61. } else {
  62. msg = fmt.Sprintf("Status: %d", status)
  63. }
  64. statusCode := 404
  65. if status >= 500 {
  66. statusCode = 500
  67. }
  68. return ierrors.Wrap(
  69. ImageResponseStatusError(msg),
  70. 1,
  71. ierrors.WithStatusCode(statusCode),
  72. ierrors.WithPublicMessage(msgSourceImageIsUnreachable),
  73. ierrors.WithShouldReport(false),
  74. )
  75. }
  76. func (e ImageResponseStatusError) Error() string { return string(e) }
  77. func newImageTooManyRedirectsError(n int) error {
  78. return ierrors.Wrap(
  79. ImageTooManyRedirectsError(fmt.Sprintf("Stopped after %d redirects", n)),
  80. 1,
  81. ierrors.WithStatusCode(http.StatusNotFound),
  82. ierrors.WithPublicMessage(msgSourceImageIsUnreachable),
  83. ierrors.WithShouldReport(false),
  84. )
  85. }
  86. func (e ImageTooManyRedirectsError) Error() string { return string(e) }
  87. func newImageRequestCanceledError(err error) error {
  88. return ierrors.Wrap(
  89. ImageRequestCanceledError{err},
  90. 2,
  91. ierrors.WithStatusCode(499),
  92. ierrors.WithPublicMessage(msgSourceImageIsUnreachable),
  93. ierrors.WithShouldReport(false),
  94. )
  95. }
  96. func (e ImageRequestCanceledError) Error() string {
  97. return fmt.Sprintf("The image request is cancelled: %s", e.error)
  98. }
  99. func (e ImageRequestCanceledError) Unwrap() error { return e.error }
  100. func newImageRequestTimeoutError(err error) error {
  101. return ierrors.Wrap(
  102. ImageRequestTimeoutError{err},
  103. 2,
  104. ierrors.WithStatusCode(http.StatusGatewayTimeout),
  105. ierrors.WithPublicMessage(msgSourceImageIsUnreachable),
  106. ierrors.WithShouldReport(false),
  107. )
  108. }
  109. func (e ImageRequestTimeoutError) Error() string {
  110. return fmt.Sprintf("The image request timed out: %s", e.error)
  111. }
  112. func (e ImageRequestTimeoutError) Unwrap() error { return e.error }
  113. func newNotModifiedError(headers map[string]string) error {
  114. return ierrors.Wrap(
  115. NotModifiedError{headers},
  116. 1,
  117. ierrors.WithStatusCode(http.StatusNotModified),
  118. ierrors.WithPublicMessage("Not modified"),
  119. ierrors.WithShouldReport(false),
  120. )
  121. }
  122. func (e NotModifiedError) Error() string { return "Not modified" }
  123. func (e NotModifiedError) Headers() map[string]string {
  124. return e.headers
  125. }
  126. func wrapError(err error) error {
  127. isTimeout := false
  128. var secArrdErr security.SourceAddressError
  129. switch {
  130. case errors.Is(err, context.DeadlineExceeded):
  131. isTimeout = true
  132. case errors.Is(err, context.Canceled):
  133. return newImageRequestCanceledError(err)
  134. case errors.As(err, &secArrdErr):
  135. return ierrors.Wrap(
  136. err,
  137. 1,
  138. ierrors.WithStatusCode(404),
  139. ierrors.WithPublicMessage(msgSourceImageIsUnreachable),
  140. ierrors.WithShouldReport(false),
  141. )
  142. default:
  143. if httpErr, ok := err.(httpError); ok {
  144. isTimeout = httpErr.Timeout()
  145. }
  146. }
  147. if isTimeout {
  148. return newImageRequestTimeoutError(err)
  149. }
  150. return ierrors.Wrap(err, 1)
  151. }