github.com/LazyboyChen7/engine@v17.12.1-ce-rc2+incompatible/api/server/httputils/errors.go (about) 1 package httputils 2 3 import ( 4 "fmt" 5 "net/http" 6 7 "github.com/docker/docker/api/errdefs" 8 "github.com/docker/docker/api/types" 9 "github.com/docker/docker/api/types/versions" 10 "github.com/gorilla/mux" 11 "github.com/sirupsen/logrus" 12 "google.golang.org/grpc" 13 "google.golang.org/grpc/codes" 14 ) 15 16 type causer interface { 17 Cause() error 18 } 19 20 // GetHTTPErrorStatusCode retrieves status code from error message. 21 func GetHTTPErrorStatusCode(err error) int { 22 if err == nil { 23 logrus.WithFields(logrus.Fields{"error": err}).Error("unexpected HTTP error handling") 24 return http.StatusInternalServerError 25 } 26 27 var statusCode int 28 29 // Stop right there 30 // Are you sure you should be adding a new error class here? Do one of the existing ones work? 31 32 // Note that the below functions are already checking the error causal chain for matches. 33 switch { 34 case errdefs.IsNotFound(err): 35 statusCode = http.StatusNotFound 36 case errdefs.IsInvalidParameter(err): 37 statusCode = http.StatusBadRequest 38 case errdefs.IsConflict(err): 39 statusCode = http.StatusConflict 40 case errdefs.IsUnauthorized(err): 41 statusCode = http.StatusUnauthorized 42 case errdefs.IsUnavailable(err): 43 statusCode = http.StatusServiceUnavailable 44 case errdefs.IsForbidden(err): 45 statusCode = http.StatusForbidden 46 case errdefs.IsNotModified(err): 47 statusCode = http.StatusNotModified 48 case errdefs.IsNotImplemented(err): 49 statusCode = http.StatusNotImplemented 50 case errdefs.IsSystem(err) || errdefs.IsUnknown(err): 51 statusCode = http.StatusInternalServerError 52 default: 53 statusCode = statusCodeFromGRPCError(err) 54 if statusCode != http.StatusInternalServerError { 55 return statusCode 56 } 57 58 if e, ok := err.(causer); ok { 59 return GetHTTPErrorStatusCode(e.Cause()) 60 } 61 62 logrus.WithFields(logrus.Fields{ 63 "module": "api", 64 "error_type": fmt.Sprintf("%T", err), 65 }).Debugf("FIXME: Got an API for which error does not match any expected type!!!: %+v", err) 66 } 67 68 if statusCode == 0 { 69 statusCode = http.StatusInternalServerError 70 } 71 72 return statusCode 73 } 74 75 func apiVersionSupportsJSONErrors(version string) bool { 76 const firstAPIVersionWithJSONErrors = "1.23" 77 return version == "" || versions.GreaterThan(version, firstAPIVersionWithJSONErrors) 78 } 79 80 // MakeErrorHandler makes an HTTP handler that decodes a Docker error and 81 // returns it in the response. 82 func MakeErrorHandler(err error) http.HandlerFunc { 83 return func(w http.ResponseWriter, r *http.Request) { 84 statusCode := GetHTTPErrorStatusCode(err) 85 vars := mux.Vars(r) 86 if apiVersionSupportsJSONErrors(vars["version"]) { 87 response := &types.ErrorResponse{ 88 Message: err.Error(), 89 } 90 WriteJSON(w, statusCode, response) 91 } else { 92 http.Error(w, grpc.ErrorDesc(err), statusCode) 93 } 94 } 95 } 96 97 // statusCodeFromGRPCError returns status code according to gRPC error 98 func statusCodeFromGRPCError(err error) int { 99 switch grpc.Code(err) { 100 case codes.InvalidArgument: // code 3 101 return http.StatusBadRequest 102 case codes.NotFound: // code 5 103 return http.StatusNotFound 104 case codes.AlreadyExists: // code 6 105 return http.StatusConflict 106 case codes.PermissionDenied: // code 7 107 return http.StatusForbidden 108 case codes.FailedPrecondition: // code 9 109 return http.StatusBadRequest 110 case codes.Unauthenticated: // code 16 111 return http.StatusUnauthorized 112 case codes.OutOfRange: // code 11 113 return http.StatusBadRequest 114 case codes.Unimplemented: // code 12 115 return http.StatusNotImplemented 116 case codes.Unavailable: // code 14 117 return http.StatusServiceUnavailable 118 default: 119 if e, ok := err.(causer); ok { 120 return statusCodeFromGRPCError(e.Cause()) 121 } 122 // codes.Canceled(1) 123 // codes.Unknown(2) 124 // codes.DeadlineExceeded(4) 125 // codes.ResourceExhausted(8) 126 // codes.Aborted(10) 127 // codes.Internal(13) 128 // codes.DataLoss(15) 129 return http.StatusInternalServerError 130 } 131 }