|
@@ -1,23 +1,15 @@
|
|
-package httputils // import "github.com/docker/docker/api/server/httputils"
|
|
|
|
|
|
+package errdefs // import "github.com/docker/docker/errdefs"
|
|
|
|
|
|
import (
|
|
import (
|
|
"fmt"
|
|
"fmt"
|
|
"net/http"
|
|
"net/http"
|
|
|
|
|
|
"github.com/docker/distribution/registry/api/errcode"
|
|
"github.com/docker/distribution/registry/api/errcode"
|
|
- "github.com/docker/docker/api/types"
|
|
|
|
- "github.com/docker/docker/api/types/versions"
|
|
|
|
- "github.com/docker/docker/errdefs"
|
|
|
|
- "github.com/gorilla/mux"
|
|
|
|
"github.com/sirupsen/logrus"
|
|
"github.com/sirupsen/logrus"
|
|
"google.golang.org/grpc/codes"
|
|
"google.golang.org/grpc/codes"
|
|
"google.golang.org/grpc/status"
|
|
"google.golang.org/grpc/status"
|
|
)
|
|
)
|
|
|
|
|
|
-type causer interface {
|
|
|
|
- Cause() error
|
|
|
|
-}
|
|
|
|
-
|
|
|
|
// GetHTTPErrorStatusCode retrieves status code from error message.
|
|
// GetHTTPErrorStatusCode retrieves status code from error message.
|
|
func GetHTTPErrorStatusCode(err error) int {
|
|
func GetHTTPErrorStatusCode(err error) int {
|
|
if err == nil {
|
|
if err == nil {
|
|
@@ -32,23 +24,23 @@ func GetHTTPErrorStatusCode(err error) int {
|
|
|
|
|
|
// Note that the below functions are already checking the error causal chain for matches.
|
|
// Note that the below functions are already checking the error causal chain for matches.
|
|
switch {
|
|
switch {
|
|
- case errdefs.IsNotFound(err):
|
|
|
|
|
|
+ case IsNotFound(err):
|
|
statusCode = http.StatusNotFound
|
|
statusCode = http.StatusNotFound
|
|
- case errdefs.IsInvalidParameter(err):
|
|
|
|
|
|
+ case IsInvalidParameter(err):
|
|
statusCode = http.StatusBadRequest
|
|
statusCode = http.StatusBadRequest
|
|
- case errdefs.IsConflict(err) || errdefs.IsAlreadyExists(err):
|
|
|
|
|
|
+ case IsConflict(err) || IsAlreadyExists(err):
|
|
statusCode = http.StatusConflict
|
|
statusCode = http.StatusConflict
|
|
- case errdefs.IsUnauthorized(err):
|
|
|
|
|
|
+ case IsUnauthorized(err):
|
|
statusCode = http.StatusUnauthorized
|
|
statusCode = http.StatusUnauthorized
|
|
- case errdefs.IsUnavailable(err):
|
|
|
|
|
|
+ case IsUnavailable(err):
|
|
statusCode = http.StatusServiceUnavailable
|
|
statusCode = http.StatusServiceUnavailable
|
|
- case errdefs.IsForbidden(err):
|
|
|
|
|
|
+ case IsForbidden(err):
|
|
statusCode = http.StatusForbidden
|
|
statusCode = http.StatusForbidden
|
|
- case errdefs.IsNotModified(err):
|
|
|
|
|
|
+ case IsNotModified(err):
|
|
statusCode = http.StatusNotModified
|
|
statusCode = http.StatusNotModified
|
|
- case errdefs.IsNotImplemented(err):
|
|
|
|
|
|
+ case IsNotImplemented(err):
|
|
statusCode = http.StatusNotImplemented
|
|
statusCode = http.StatusNotImplemented
|
|
- case errdefs.IsSystem(err) || errdefs.IsUnknown(err) || errdefs.IsDataLoss(err) || errdefs.IsDeadline(err) || errdefs.IsCancelled(err):
|
|
|
|
|
|
+ case IsSystem(err) || IsUnknown(err) || IsDataLoss(err) || IsDeadline(err) || IsCancelled(err):
|
|
statusCode = http.StatusInternalServerError
|
|
statusCode = http.StatusInternalServerError
|
|
default:
|
|
default:
|
|
statusCode = statusCodeFromGRPCError(err)
|
|
statusCode = statusCodeFromGRPCError(err)
|
|
@@ -76,26 +68,50 @@ func GetHTTPErrorStatusCode(err error) int {
|
|
return statusCode
|
|
return statusCode
|
|
}
|
|
}
|
|
|
|
|
|
-func apiVersionSupportsJSONErrors(version string) bool {
|
|
|
|
- const firstAPIVersionWithJSONErrors = "1.23"
|
|
|
|
- return version == "" || versions.GreaterThan(version, firstAPIVersionWithJSONErrors)
|
|
|
|
-}
|
|
|
|
|
|
+// FromStatusCode creates an errdef error, based on the provided HTTP status-code
|
|
|
|
+func FromStatusCode(err error, statusCode int) error {
|
|
|
|
+ if err == nil {
|
|
|
|
+ return err
|
|
|
|
+ }
|
|
|
|
+ switch statusCode {
|
|
|
|
+ case http.StatusNotFound:
|
|
|
|
+ err = NotFound(err)
|
|
|
|
+ case http.StatusBadRequest:
|
|
|
|
+ err = InvalidParameter(err)
|
|
|
|
+ case http.StatusConflict:
|
|
|
|
+ err = Conflict(err)
|
|
|
|
+ case http.StatusUnauthorized:
|
|
|
|
+ err = Unauthorized(err)
|
|
|
|
+ case http.StatusServiceUnavailable:
|
|
|
|
+ err = Unavailable(err)
|
|
|
|
+ case http.StatusForbidden:
|
|
|
|
+ err = Forbidden(err)
|
|
|
|
+ case http.StatusNotModified:
|
|
|
|
+ err = NotModified(err)
|
|
|
|
+ case http.StatusNotImplemented:
|
|
|
|
+ err = NotImplemented(err)
|
|
|
|
+ case http.StatusInternalServerError:
|
|
|
|
+ if !IsSystem(err) && !IsUnknown(err) && !IsDataLoss(err) && !IsDeadline(err) && !IsCancelled(err) {
|
|
|
|
+ err = System(err)
|
|
|
|
+ }
|
|
|
|
+ default:
|
|
|
|
+ logrus.WithFields(logrus.Fields{
|
|
|
|
+ "module": "api",
|
|
|
|
+ "status_code": fmt.Sprintf("%d", statusCode),
|
|
|
|
+ }).Debugf("FIXME: Got an status-code for which error does not match any expected type!!!: %d", statusCode)
|
|
|
|
|
|
-// MakeErrorHandler makes an HTTP handler that decodes a Docker error and
|
|
|
|
-// returns it in the response.
|
|
|
|
-func MakeErrorHandler(err error) http.HandlerFunc {
|
|
|
|
- return func(w http.ResponseWriter, r *http.Request) {
|
|
|
|
- statusCode := GetHTTPErrorStatusCode(err)
|
|
|
|
- vars := mux.Vars(r)
|
|
|
|
- if apiVersionSupportsJSONErrors(vars["version"]) {
|
|
|
|
- response := &types.ErrorResponse{
|
|
|
|
- Message: err.Error(),
|
|
|
|
- }
|
|
|
|
- WriteJSON(w, statusCode, response)
|
|
|
|
- } else {
|
|
|
|
- http.Error(w, status.Convert(err).Message(), statusCode)
|
|
|
|
|
|
+ switch {
|
|
|
|
+ case statusCode >= 200 && statusCode < 400:
|
|
|
|
+ // it's a client error
|
|
|
|
+ case statusCode >= 400 && statusCode < 500:
|
|
|
|
+ err = InvalidParameter(err)
|
|
|
|
+ case statusCode >= 500 && statusCode < 600:
|
|
|
|
+ err = System(err)
|
|
|
|
+ default:
|
|
|
|
+ err = Unknown(err)
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
+ return err
|
|
}
|
|
}
|
|
|
|
|
|
// statusCodeFromGRPCError returns status code according to gRPC error
|
|
// statusCodeFromGRPCError returns status code according to gRPC error
|