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  }