errors.go 1.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172
  1. package client
  2. import (
  3. "encoding/json"
  4. "fmt"
  5. "io"
  6. "io/ioutil"
  7. "net/http"
  8. "github.com/docker/distribution/registry/api/errcode"
  9. )
  10. // UnexpectedHTTPStatusError is returned when an unexpected HTTP status is
  11. // returned when making a registry api call.
  12. type UnexpectedHTTPStatusError struct {
  13. Status string
  14. }
  15. func (e *UnexpectedHTTPStatusError) Error() string {
  16. return fmt.Sprintf("Received unexpected HTTP status: %s", e.Status)
  17. }
  18. // UnexpectedHTTPResponseError is returned when an expected HTTP status code
  19. // is returned, but the content was unexpected and failed to be parsed.
  20. type UnexpectedHTTPResponseError struct {
  21. ParseErr error
  22. Response []byte
  23. }
  24. func (e *UnexpectedHTTPResponseError) Error() string {
  25. return fmt.Sprintf("Error parsing HTTP response: %s: %q", e.ParseErr.Error(), string(e.Response))
  26. }
  27. func parseHTTPErrorResponse(r io.Reader) error {
  28. var errors errcode.Errors
  29. body, err := ioutil.ReadAll(r)
  30. if err != nil {
  31. return err
  32. }
  33. if err := json.Unmarshal(body, &errors); err != nil {
  34. return &UnexpectedHTTPResponseError{
  35. ParseErr: err,
  36. Response: body,
  37. }
  38. }
  39. return errors
  40. }
  41. // HandleErrorResponse returns error parsed from HTTP response for an
  42. // unsuccessful HTTP response code (in the range 400 - 499 inclusive). An
  43. // UnexpectedHTTPStatusError returned for response code outside of expected
  44. // range.
  45. func HandleErrorResponse(resp *http.Response) error {
  46. if resp.StatusCode == 401 {
  47. err := parseHTTPErrorResponse(resp.Body)
  48. if uErr, ok := err.(*UnexpectedHTTPResponseError); ok {
  49. return errcode.ErrorCodeUnauthorized.WithDetail(uErr.Response)
  50. }
  51. return err
  52. }
  53. if resp.StatusCode >= 400 && resp.StatusCode < 500 {
  54. return parseHTTPErrorResponse(resp.Body)
  55. }
  56. return &UnexpectedHTTPStatusError{Status: resp.Status}
  57. }
  58. // SuccessStatus returns true if the argument is a successful HTTP response
  59. // code (in the range 200 - 399 inclusive).
  60. func SuccessStatus(status int) bool {
  61. return status >= 200 && status <= 399
  62. }