github.com/zhuohuang-hust/src-cbuild@v0.0.0-20230105071821-c7aab3e7c840/api/server/httputils/errors.go (about) 1 package httputils 2 3 import ( 4 "net/http" 5 "strings" 6 "fmt" 7 8 "github.com/Sirupsen/logrus" 9 "github.com/docker/docker/api/types" 10 "github.com/docker/docker/api/types/versions" 11 "github.com/gorilla/mux" 12 "google.golang.org/grpc" 13 ) 14 15 // httpStatusError is an interface 16 // that errors with custom status codes 17 // implement to tell the api layer 18 // which response status to set. 19 type httpStatusError interface { 20 HTTPErrorStatusCode() int 21 } 22 23 // inputValidationError is an interface 24 // that errors generated by invalid 25 // inputs can implement to tell the 26 // api layer to set a 400 status code 27 // in the response. 28 type inputValidationError interface { 29 IsValidationError() bool 30 } 31 32 // GetHTTPErrorStatusCode retrieves status code from error message 33 func GetHTTPErrorStatusCode(err error) int { 34 fmt.Println("api/server/httputils/errors.go GetHTTPErrorStatusCode()") 35 if err == nil { 36 logrus.WithFields(logrus.Fields{"error": err}).Error("unexpected HTTP error handling") 37 return http.StatusInternalServerError 38 } 39 40 var statusCode int 41 errMsg := err.Error() 42 43 switch e := err.(type) { 44 case httpStatusError: 45 statusCode = e.HTTPErrorStatusCode() 46 fmt.Println("api/server/httputils/errors.go GetHTTPErrorStatusCode() httpStatusError statusCode : ", statusCode) 47 case inputValidationError: 48 statusCode = http.StatusBadRequest 49 fmt.Println("api/server/httputils/errors.go GetHTTPErrorStatusCode() inputValidationError statusCode : ", statusCode) 50 default: 51 // FIXME: this is brittle and should not be necessary, but we still need to identify if 52 // there are errors falling back into this logic. 53 // If we need to differentiate between different possible error types, 54 // we should create appropriate error types that implement the httpStatusError interface. 55 errStr := strings.ToLower(errMsg) 56 for _, status := range []struct { 57 keyword string 58 code int 59 }{ 60 {"not found", http.StatusNotFound}, 61 {"no such", http.StatusNotFound}, 62 {"bad parameter", http.StatusBadRequest}, 63 {"no command", http.StatusBadRequest}, 64 {"conflict", http.StatusConflict}, 65 {"impossible", http.StatusNotAcceptable}, 66 {"wrong login/password", http.StatusUnauthorized}, 67 {"unauthorized", http.StatusUnauthorized}, 68 {"hasn't been activated", http.StatusForbidden}, 69 {"this node", http.StatusServiceUnavailable}, 70 } { 71 if strings.Contains(errStr, status.keyword) { 72 statusCode = status.code 73 fmt.Println("api/server/httputils/errors.go GetHTTPErrorStatusCode() stringscontains statusCode : ", statusCode) 74 break 75 } 76 } 77 } 78 79 if statusCode == 0 { 80 statusCode = http.StatusInternalServerError 81 } 82 83 fmt.Println("api/server/httputils/errors.go GetHTTPErrorStatusCode() end statusCode : ", statusCode) 84 85 return statusCode 86 } 87 88 func apiVersionSupportsJSONErrors(version string) bool { 89 const firstAPIVersionWithJSONErrors = "1.23" 90 return version == "" || versions.GreaterThan(version, firstAPIVersionWithJSONErrors) 91 } 92 93 // MakeErrorHandler makes an HTTP handler that decodes a Docker error and 94 // returns it in the response. 95 func MakeErrorHandler(err error) http.HandlerFunc { 96 return func(w http.ResponseWriter, r *http.Request) { 97 statusCode := GetHTTPErrorStatusCode(err) 98 vars := mux.Vars(r) 99 if apiVersionSupportsJSONErrors(vars["version"]) { 100 response := &types.ErrorResponse{ 101 Message: err.Error(), 102 } 103 WriteJSON(w, statusCode, response) 104 } else { 105 http.Error(w, grpc.ErrorDesc(err), statusCode) 106 } 107 } 108 }