errors.go 3.9 KB

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