github.com/Heebron/moby@v0.0.0-20221111184709-6eab4f55faf7/api/server/httpstatus/status.go (about) 1 package httpstatus // import "github.com/docker/docker/api/server/httpstatus" 2 3 import ( 4 "fmt" 5 "net/http" 6 7 containerderrors "github.com/containerd/containerd/errdefs" 8 "github.com/docker/distribution/registry/api/errcode" 9 "github.com/docker/docker/errdefs" 10 "github.com/sirupsen/logrus" 11 "google.golang.org/grpc/codes" 12 "google.golang.org/grpc/status" 13 ) 14 15 type causer interface { 16 Cause() error 17 } 18 19 // FromError retrieves status code from error message. 20 func FromError(err error) int { 21 if err == nil { 22 logrus.WithFields(logrus.Fields{"error": err}).Error("unexpected HTTP error handling") 23 return http.StatusInternalServerError 24 } 25 26 var statusCode int 27 28 // Stop right there 29 // Are you sure you should be adding a new error class here? Do one of the existing ones work? 30 31 // Note that the below functions are already checking the error causal chain for matches. 32 switch { 33 case errdefs.IsNotFound(err): 34 statusCode = http.StatusNotFound 35 case errdefs.IsInvalidParameter(err): 36 statusCode = http.StatusBadRequest 37 case errdefs.IsConflict(err): 38 statusCode = http.StatusConflict 39 case errdefs.IsUnauthorized(err): 40 statusCode = http.StatusUnauthorized 41 case errdefs.IsUnavailable(err): 42 statusCode = http.StatusServiceUnavailable 43 case errdefs.IsForbidden(err): 44 statusCode = http.StatusForbidden 45 case errdefs.IsNotModified(err): 46 statusCode = http.StatusNotModified 47 case errdefs.IsNotImplemented(err): 48 statusCode = http.StatusNotImplemented 49 case errdefs.IsSystem(err) || errdefs.IsUnknown(err) || errdefs.IsDataLoss(err) || errdefs.IsDeadline(err) || errdefs.IsCancelled(err): 50 statusCode = http.StatusInternalServerError 51 default: 52 statusCode = statusCodeFromGRPCError(err) 53 if statusCode != http.StatusInternalServerError { 54 return statusCode 55 } 56 statusCode = statusCodeFromContainerdError(err) 57 if statusCode != http.StatusInternalServerError { 58 return statusCode 59 } 60 statusCode = statusCodeFromDistributionError(err) 61 if statusCode != http.StatusInternalServerError { 62 return statusCode 63 } 64 if e, ok := err.(causer); ok { 65 return FromError(e.Cause()) 66 } 67 68 logrus.WithFields(logrus.Fields{ 69 "module": "api", 70 "error_type": fmt.Sprintf("%T", err), 71 }).Debugf("FIXME: Got an API for which error does not match any expected type!!!: %+v", err) 72 } 73 74 if statusCode == 0 { 75 statusCode = http.StatusInternalServerError 76 } 77 78 return statusCode 79 } 80 81 // statusCodeFromGRPCError returns status code according to gRPC error 82 func statusCodeFromGRPCError(err error) int { 83 switch status.Code(err) { 84 case codes.InvalidArgument: // code 3 85 return http.StatusBadRequest 86 case codes.NotFound: // code 5 87 return http.StatusNotFound 88 case codes.AlreadyExists: // code 6 89 return http.StatusConflict 90 case codes.PermissionDenied: // code 7 91 return http.StatusForbidden 92 case codes.FailedPrecondition: // code 9 93 return http.StatusBadRequest 94 case codes.Unauthenticated: // code 16 95 return http.StatusUnauthorized 96 case codes.OutOfRange: // code 11 97 return http.StatusBadRequest 98 case codes.Unimplemented: // code 12 99 return http.StatusNotImplemented 100 case codes.Unavailable: // code 14 101 return http.StatusServiceUnavailable 102 default: 103 // codes.Canceled(1) 104 // codes.Unknown(2) 105 // codes.DeadlineExceeded(4) 106 // codes.ResourceExhausted(8) 107 // codes.Aborted(10) 108 // codes.Internal(13) 109 // codes.DataLoss(15) 110 return http.StatusInternalServerError 111 } 112 } 113 114 // statusCodeFromDistributionError returns status code according to registry errcode 115 // code is loosely based on errcode.ServeJSON() in docker/distribution 116 func statusCodeFromDistributionError(err error) int { 117 switch errs := err.(type) { 118 case errcode.Errors: 119 if len(errs) < 1 { 120 return http.StatusInternalServerError 121 } 122 if _, ok := errs[0].(errcode.ErrorCoder); ok { 123 return statusCodeFromDistributionError(errs[0]) 124 } 125 case errcode.ErrorCoder: 126 return errs.ErrorCode().Descriptor().HTTPStatusCode 127 } 128 return http.StatusInternalServerError 129 } 130 131 // statusCodeFromContainerdError returns status code for containerd errors when 132 // consumed directly (not through gRPC) 133 func statusCodeFromContainerdError(err error) int { 134 switch { 135 case containerderrors.IsInvalidArgument(err): 136 return http.StatusBadRequest 137 case containerderrors.IsNotFound(err): 138 return http.StatusNotFound 139 case containerderrors.IsAlreadyExists(err): 140 return http.StatusConflict 141 case containerderrors.IsFailedPrecondition(err): 142 return http.StatusPreconditionFailed 143 case containerderrors.IsUnavailable(err): 144 return http.StatusServiceUnavailable 145 case containerderrors.IsNotImplemented(err): 146 return http.StatusNotImplemented 147 default: 148 return http.StatusInternalServerError 149 } 150 }