errors.go 1.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869
  1. package httputils
  2. import (
  3. "net/http"
  4. "strings"
  5. "github.com/Sirupsen/logrus"
  6. )
  7. // httpStatusError is an interface
  8. // that errors with custom status codes
  9. // implement to tell the api layer
  10. // which response status to set.
  11. type httpStatusError interface {
  12. HTTPErrorStatusCode() int
  13. }
  14. // inputValidationError is an interface
  15. // that errors generated by invalid
  16. // inputs can implement to tell the
  17. // api layer to set a 400 status code
  18. // in the response.
  19. type inputValidationError interface {
  20. IsValidationError() bool
  21. }
  22. // WriteError decodes a specific docker error and sends it in the response.
  23. func WriteError(w http.ResponseWriter, err error) {
  24. if err == nil || w == nil {
  25. logrus.WithFields(logrus.Fields{"error": err, "writer": w}).Error("unexpected HTTP error handling")
  26. return
  27. }
  28. var statusCode int
  29. errMsg := err.Error()
  30. switch e := err.(type) {
  31. case httpStatusError:
  32. statusCode = e.HTTPErrorStatusCode()
  33. case inputValidationError:
  34. statusCode = http.StatusBadRequest
  35. default:
  36. // FIXME: this is brittle and should not be necessary, but we still need to identify if
  37. // there are errors falling back into this logic.
  38. // If we need to differentiate between different possible error types,
  39. // we should create appropriate error types that implement the httpStatusError interface.
  40. errStr := strings.ToLower(errMsg)
  41. for keyword, status := range map[string]int{
  42. "not found": http.StatusNotFound,
  43. "no such": http.StatusNotFound,
  44. "bad parameter": http.StatusBadRequest,
  45. "conflict": http.StatusConflict,
  46. "impossible": http.StatusNotAcceptable,
  47. "wrong login/password": http.StatusUnauthorized,
  48. "hasn't been activated": http.StatusForbidden,
  49. } {
  50. if strings.Contains(errStr, keyword) {
  51. statusCode = status
  52. break
  53. }
  54. }
  55. }
  56. if statusCode == 0 {
  57. statusCode = http.StatusInternalServerError
  58. }
  59. http.Error(w, errMsg, statusCode)
  60. }