diff --git a/api/server/httputils/errors.go b/api/server/httputils/errors.go index 88e83139d1..2abdce2bcf 100644 --- a/api/server/httputils/errors.go +++ b/api/server/httputils/errors.go @@ -4,6 +4,7 @@ import ( "fmt" "net/http" + "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" @@ -54,7 +55,10 @@ func GetHTTPErrorStatusCode(err error) int { if statusCode != http.StatusInternalServerError { return statusCode } - + statusCode = statusCodeFromDistributionError(err) + if statusCode != http.StatusInternalServerError { + return statusCode + } if e, ok := err.(causer); ok { return GetHTTPErrorStatusCode(e.Cause()) } @@ -129,3 +133,24 @@ func statusCodeFromGRPCError(err error) int { return http.StatusInternalServerError } } + +// statusCodeFromDistributionError returns status code according to registry errcode +// code is loosely based on errcode.ServeJSON() in docker/distribution +func statusCodeFromDistributionError(err error) int { + switch errs := err.(type) { + case errcode.Errors: + if len(errs) < 1 { + return http.StatusInternalServerError + } + if _, ok := errs[0].(errcode.ErrorCoder); ok { + return statusCodeFromDistributionError(errs[0]) + } + case errcode.ErrorCoder: + return errs.ErrorCode().Descriptor().HTTPStatusCode + default: + if e, ok := err.(causer); ok { + return statusCodeFromDistributionError(e.Cause()) + } + } + return http.StatusInternalServerError +} diff --git a/api/server/router/distribution/distribution_routes.go b/api/server/router/distribution/distribution_routes.go index 531dba69fc..d285728382 100644 --- a/api/server/router/distribution/distribution_routes.go +++ b/api/server/router/distribution/distribution_routes.go @@ -14,6 +14,7 @@ import ( "github.com/docker/docker/api/server/httputils" "github.com/docker/docker/api/types" registrytypes "github.com/docker/docker/api/types/registry" + "github.com/docker/docker/errdefs" "github.com/opencontainers/image-spec/specs-go/v1" "github.com/pkg/errors" ) @@ -42,9 +43,10 @@ func (s *distributionRouter) getDistributionInfo(ctx context.Context, w http.Res image := vars["name"] + // TODO why is reference.ParseAnyReference() / reference.ParseNormalizedNamed() not using the reference.ErrTagInvalidFormat (and so on) errors? ref, err := reference.ParseAnyReference(image) if err != nil { - return err + return errdefs.InvalidParameter(err) } namedRef, ok := ref.(reference.Named) if !ok { @@ -52,7 +54,7 @@ func (s *distributionRouter) getDistributionInfo(ctx context.Context, w http.Res // full image ID return errors.Errorf("no manifest found for full image ID") } - return errors.Errorf("unknown image reference format: %s", image) + return errdefs.InvalidParameter(errors.Errorf("unknown image reference format: %s", image)) } distrepo, _, err := s.backend.GetRepository(ctx, namedRef, config) @@ -66,7 +68,7 @@ func (s *distributionRouter) getDistributionInfo(ctx context.Context, w http.Res taggedRef, ok := namedRef.(reference.NamedTagged) if !ok { - return errors.Errorf("image reference not tagged: %s", image) + return errdefs.InvalidParameter(errors.Errorf("image reference not tagged: %s", image)) } descriptor, err := distrepo.Tags(ctx).Get(ctx, taggedRef.Tag()) @@ -92,6 +94,16 @@ func (s *distributionRouter) getDistributionInfo(ctx context.Context, w http.Res } mnfst, err := mnfstsrvc.Get(ctx, distributionInspect.Descriptor.Digest) if err != nil { + switch err { + case reference.ErrReferenceInvalidFormat, + reference.ErrTagInvalidFormat, + reference.ErrDigestInvalidFormat, + reference.ErrNameContainsUppercase, + reference.ErrNameEmpty, + reference.ErrNameTooLong, + reference.ErrNameNotCanonical: + return errdefs.InvalidParameter(err) + } return err } diff --git a/daemon/images/image_pull.go b/daemon/images/image_pull.go index 3e6b433037..f2b6894861 100644 --- a/daemon/images/image_pull.go +++ b/daemon/images/image_pull.go @@ -92,7 +92,7 @@ func (i *ImageService) GetRepository(ctx context.Context, ref reference.Named, a // get repository info repoInfo, err := i.registryService.ResolveRepository(ref) if err != nil { - return nil, false, err + return nil, false, errdefs.InvalidParameter(err) } // makes sure name is not empty or `scratch` if err := distribution.ValidateRepoName(repoInfo.Name); err != nil {