diff --git a/registry/api/errcode/errors.go b/registry/api/errcode/errors.go index ce3c06246..c46670a13 100644 --- a/registry/api/errcode/errors.go +++ b/registry/api/errcode/errors.go @@ -55,8 +55,8 @@ var errorDescriptors = []ErrorDescriptor{ } // LoadErrors will register a new set of Errors into the system -func LoadErrors(errs *[]ErrorDescriptor) { - for _, descriptor := range *errs { +func LoadErrors(errs []ErrorDescriptor) { + for _, descriptor := range errs { if _, ok := idToDescriptors[descriptor.Value]; ok { panic(fmt.Sprintf("ErrorValue %s is already registered", descriptor.Value)) } @@ -123,28 +123,28 @@ func (ec *ErrorCode) UnmarshalText(text []byte) error { // Error provides a wrapper around ErrorCode with extra Details provided. type Error struct { - Code ErrorCode `json:"code"` - Message string `json:"message,omitempty"` - Detail interface{} `json:"detail,omitempty"` + Code ErrorCode `json:"code"` + Detail interface{} `json:"detail,omitempty"` } // Error returns a human readable representation of the error. func (e Error) Error() string { return fmt.Sprintf("%s: %s", strings.ToLower(strings.Replace(e.Code.String(), "_", " ", -1)), - e.Message) + e.Code.Message()) +} + +// Message returned the human-readable error message for this Error +func (e Error) Message() string { + return e.Code.Message() } // Errors provides the envelope for multiple errors and a few sugar methods // for use within the application. -type Errors struct { - Errors []Error `json:"errors,omitempty"` -} +type Errors []Error -// Push pushes an error on to the error stack, with the optional detail -// argument. It is a programming error (ie panic) to push more than one -// detail at a time. -func (errs *Errors) Push(code ErrorCode, details ...interface{}) { +// NewError creates a new Error struct based on the passed-in info +func NewError(code ErrorCode, details ...interface{}) Error { if len(details) > 1 { panic("please specify zero or one detail items for this error") } @@ -158,49 +158,33 @@ func (errs *Errors) Push(code ErrorCode, details ...interface{}) { detail = err.Error() } - errs.PushErr(Error{ - Code: code, - Message: code.Message(), - Detail: detail, - }) -} - -// PushErr pushes an error interface onto the error stack. -func (errs *Errors) PushErr(err error) { - switch err.(type) { - case Error: - errs.Errors = append(errs.Errors, err.(Error)) - default: - errs.Errors = append(errs.Errors, Error{Message: err.Error()}) + return Error{ + Code: code, + Detail: detail, } } -func (errs *Errors) Error() string { - switch errs.Len() { +func (errs Errors) Error() string { + switch len(errs) { case 0: return "" case 1: - return errs.Errors[0].Error() + return errs[0].Error() default: msg := "errors:\n" - for _, err := range errs.Errors { + for _, err := range errs { msg += err.Error() + "\n" } return msg } } -// Clear clears the errors. -func (errs *Errors) Clear() { - errs.Errors = nil -} - // Len returns the current number of errors. -func (errs *Errors) Len() int { - return len(errs.Errors) +func (errs Errors) Len() int { + return len(errs) } // init loads the default errors that are part of the errcode package func init() { - LoadErrors(&errorDescriptors) + LoadErrors(errorDescriptors) } diff --git a/registry/api/v2/errors.go b/registry/api/v2/errors.go index fc61549ba..9655dba86 100644 --- a/registry/api/v2/errors.go +++ b/registry/api/v2/errors.go @@ -188,5 +188,5 @@ var errorDescriptors = []errcode.ErrorDescriptor{ // init registers our errors with the errcode system func init() { - errcode.LoadErrors(&errorDescriptors) + errcode.LoadErrors(errorDescriptors) } diff --git a/registry/client/blob_writer_test.go b/registry/client/blob_writer_test.go index 3fdeb6ee3..74545b065 100644 --- a/registry/client/blob_writer_test.go +++ b/registry/client/blob_writer_test.go @@ -86,15 +86,12 @@ func TestUploadReadFrom(t *testing.T) { Response: testutil.Response{ StatusCode: http.StatusBadRequest, Body: []byte(` - { - "errors": [ + [ { "code": "BLOB_UPLOAD_INVALID", - "message": "invalid upload identifier", "detail": "more detail" } - ] - }`), + ] `), }, }, // Test 400 invalid json @@ -162,17 +159,17 @@ func TestUploadReadFrom(t *testing.T) { if err == nil { t.Fatalf("Expected error when not found") } - if uploadErr, ok := err.(*errcode.Errors); !ok { + if uploadErr, ok := err.(errcode.Errors); !ok { t.Fatalf("Wrong error type %T: %s", err, err) - } else if len(uploadErr.Errors) != 1 { - t.Fatalf("Unexpected number of errors: %d, expected 1", len(uploadErr.Errors)) + } else if len(uploadErr) != 1 { + t.Fatalf("Unexpected number of errors: %d, expected 1", len(uploadErr)) } else { - v2Err := uploadErr.Errors[0] + v2Err := uploadErr[0] if v2Err.Code != v2.ErrorCodeBlobUploadInvalid { t.Fatalf("Unexpected error code: %s, expected %d", v2Err.Code.String(), v2.ErrorCodeBlobUploadInvalid) } - if expected := "invalid upload identifier"; v2Err.Message != expected { - t.Fatalf("Unexpected error message: %s, expected %s", v2Err.Message, expected) + if expected := "blob upload invalid"; v2Err.Message() != expected { + t.Fatalf("Unexpected error message: %s, expected %s", v2Err.Message(), expected) } if expected := "more detail"; v2Err.Detail.(string) != expected { t.Fatalf("Unexpected error message: %s, expected %s", v2Err.Detail.(string), expected) diff --git a/registry/client/errors.go b/registry/client/errors.go index ef25dddf0..e743533b9 100644 --- a/registry/client/errors.go +++ b/registry/client/errors.go @@ -45,7 +45,7 @@ func parseHTTPErrorResponse(r io.Reader) error { Response: body, } } - return &errors + return errors } func handleErrorResponse(resp *http.Response) error { @@ -53,9 +53,8 @@ func handleErrorResponse(resp *http.Response) error { err := parseHTTPErrorResponse(resp.Body) if uErr, ok := err.(*UnexpectedHTTPResponseError); ok { return &errcode.Error{ - Code: v2.ErrorCodeUnauthorized, - Message: "401 Unauthorized", - Detail: uErr.Response, + Code: v2.ErrorCodeUnauthorized, + Detail: uErr.Response, } } return err diff --git a/registry/client/repository_test.go b/registry/client/repository_test.go index 24946ed5f..7dbe97cf7 100644 --- a/registry/client/repository_test.go +++ b/registry/client/repository_test.go @@ -676,7 +676,7 @@ func TestManifestUnauthorized(t *testing.T) { if v2Err.Code != v2.ErrorCodeUnauthorized { t.Fatalf("Unexpected error code: %s", v2Err.Code.String()) } - if expected := "401 Unauthorized"; v2Err.Message != expected { - t.Fatalf("Unexpected message value: %s, expected %s", v2Err.Message, expected) + if expected := errcode.ErrorCode(v2.ErrorCodeUnauthorized).Message(); v2Err.Message() != expected { + t.Fatalf("Unexpected message value: %s, expected %s", v2Err.Message(), expected) } } diff --git a/registry/handlers/api_test.go b/registry/handlers/api_test.go index c5a994537..146fcf4c9 100644 --- a/registry/handlers/api_test.go +++ b/registry/handlers/api_test.go @@ -760,7 +760,7 @@ func checkBodyHasErrorCodes(t *testing.T, msg string, resp *http.Response, error t.Fatalf("unexpected error decoding error response: %v", err) } - if len(errs.Errors) == 0 { + if len(errs) == 0 { t.Fatalf("expected errors in response") } @@ -780,7 +780,7 @@ func checkBodyHasErrorCodes(t *testing.T, msg string, resp *http.Response, error counts[code] = 0 } - for _, err := range errs.Errors { + for _, err := range errs { if _, ok := expected[err.Code]; !ok { t.Fatalf("unexpected error code %v encountered during %s: %s ", err.Code, msg, string(p)) } diff --git a/registry/handlers/app.go b/registry/handlers/app.go index 2747ac8b1..12c6e2274 100644 --- a/registry/handlers/app.go +++ b/registry/handlers/app.go @@ -346,9 +346,9 @@ func (app *App) dispatcher(dispatch dispatchFunc) http.Handler { switch err := err.(type) { case distribution.ErrRepositoryUnknown: - context.Errors.Push(v2.ErrorCodeNameUnknown, err) + context.Errors = append(context.Errors, errcode.NewError(v2.ErrorCodeNameUnknown, err)) case distribution.ErrRepositoryNameInvalid: - context.Errors.Push(v2.ErrorCodeNameInvalid, err) + context.Errors = append(context.Errors, errcode.NewError(v2.ErrorCodeNameInvalid, err)) } serveJSON(w, context.Errors) @@ -363,7 +363,7 @@ func (app *App) dispatcher(dispatch dispatchFunc) http.Handler { context.Repository, err = applyRepoMiddleware(context.Repository, app.Config.Middleware["repository"]) if err != nil { ctxu.GetLogger(context).Errorf("error initializing repository middleware: %v", err) - context.Errors.Push(errcode.ErrorCodeUnknown, err) + context.Errors = append(context.Errors, errcode.NewError(errcode.ErrorCodeUnknown, err)) serveJSON(w, context.Errors) return @@ -383,9 +383,9 @@ func (app *App) dispatcher(dispatch dispatchFunc) http.Handler { } func (app *App) logError(context context.Context, errors errcode.Errors) { - for _, e := range errors.Errors { + for _, e := range errors { c := ctxu.WithValue(context, "err.code", e.Code) - c = ctxu.WithValue(c, "err.message", e.Message) + c = ctxu.WithValue(c, "err.message", e.Code.Message()) c = ctxu.WithValue(c, "err.detail", e.Detail) c = ctxu.WithLogger(c, ctxu.GetLogger(c, "err.code", @@ -441,7 +441,7 @@ func (app *App) authorized(w http.ResponseWriter, r *http.Request, context *Cont // proceed. var errs errcode.Errors - errs.Push(v2.ErrorCodeUnauthorized) + errs = append(errs, errcode.NewError(v2.ErrorCodeUnauthorized)) serveJSON(w, errs) return fmt.Errorf("forbidden: no repository name") @@ -464,7 +464,7 @@ func (app *App) authorized(w http.ResponseWriter, r *http.Request, context *Cont err.ServeHTTP(w, r) var errs errcode.Errors - errs.Push(v2.ErrorCodeUnauthorized, accessRecords) + errs = append(errs, errcode.NewError(v2.ErrorCodeUnauthorized, accessRecords)) serveJSON(w, errs) default: // This condition is a potential security problem either in diff --git a/registry/handlers/app_test.go b/registry/handlers/app_test.go index da76dc0de..0520cb403 100644 --- a/registry/handlers/app_test.go +++ b/registry/handlers/app_test.go @@ -203,8 +203,8 @@ func TestNewApp(t *testing.T) { t.Fatalf("error decoding error response: %v", err) } - if errs.Errors[0].Code != v2.ErrorCodeUnauthorized { - t.Fatalf("unexpected error code: %v != %v", errs.Errors[0].Code, v2.ErrorCodeUnauthorized) + if errs[0].Code != v2.ErrorCodeUnauthorized { + t.Fatalf("unexpected error code: %v != %v", errs[0].Code, v2.ErrorCodeUnauthorized) } } diff --git a/registry/handlers/blob.go b/registry/handlers/blob.go index 56699fe9a..fa9f576aa 100644 --- a/registry/handlers/blob.go +++ b/registry/handlers/blob.go @@ -18,12 +18,12 @@ func blobDispatcher(ctx *Context, r *http.Request) http.Handler { if err == errDigestNotAvailable { return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { - ctx.Errors.Push(v2.ErrorCodeDigestInvalid, err) + ctx.Errors = append(ctx.Errors, errcode.NewError(v2.ErrorCodeDigestInvalid, err)) }) } return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { - ctx.Errors.Push(v2.ErrorCodeDigestInvalid, err) + ctx.Errors = append(ctx.Errors, errcode.NewError(v2.ErrorCodeDigestInvalid, err)) }) } @@ -53,16 +53,16 @@ func (bh *blobHandler) GetBlob(w http.ResponseWriter, r *http.Request) { desc, err := blobs.Stat(bh, bh.Digest) if err != nil { if err == distribution.ErrBlobUnknown { - bh.Errors.Push(v2.ErrorCodeBlobUnknown, bh.Digest) + bh.Errors = append(bh.Errors, errcode.NewError(v2.ErrorCodeBlobUnknown, bh.Digest)) } else { - bh.Errors.Push(errcode.ErrorCodeUnknown, err) + bh.Errors = append(bh.Errors, errcode.NewError(errcode.ErrorCodeUnknown, err)) } return } if err := blobs.ServeBlob(bh, w, r, desc.Digest); err != nil { context.GetLogger(bh).Debugf("unexpected error getting blob HTTP handler: %v", err) - bh.Errors.Push(errcode.ErrorCodeUnknown, err) + bh.Errors = append(bh.Errors, errcode.NewError(errcode.ErrorCodeUnknown, err)) return } } diff --git a/registry/handlers/blobupload.go b/registry/handlers/blobupload.go index 7046edd35..7e8c39622 100644 --- a/registry/handlers/blobupload.go +++ b/registry/handlers/blobupload.go @@ -37,7 +37,7 @@ func blobUploadDispatcher(ctx *Context, r *http.Request) http.Handler { if err != nil { return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { ctxu.GetLogger(ctx).Infof("error resolving upload: %v", err) - buh.Errors.Push(v2.ErrorCodeBlobUploadInvalid, err) + buh.Errors = append(buh.Errors, errcode.NewError(v2.ErrorCodeBlobUploadInvalid, err)) }) } buh.State = state @@ -45,14 +45,14 @@ func blobUploadDispatcher(ctx *Context, r *http.Request) http.Handler { if state.Name != ctx.Repository.Name() { return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { ctxu.GetLogger(ctx).Infof("mismatched repository name in upload state: %q != %q", state.Name, buh.Repository.Name()) - buh.Errors.Push(v2.ErrorCodeBlobUploadInvalid, err) + buh.Errors = append(buh.Errors, errcode.NewError(v2.ErrorCodeBlobUploadInvalid, err)) }) } if state.UUID != buh.UUID { return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { ctxu.GetLogger(ctx).Infof("mismatched uuid in upload state: %q != %q", state.UUID, buh.UUID) - buh.Errors.Push(v2.ErrorCodeBlobUploadInvalid, err) + buh.Errors = append(buh.Errors, errcode.NewError(v2.ErrorCodeBlobUploadInvalid, err)) }) } @@ -62,12 +62,12 @@ func blobUploadDispatcher(ctx *Context, r *http.Request) http.Handler { ctxu.GetLogger(ctx).Errorf("error resolving upload: %v", err) if err == distribution.ErrBlobUploadUnknown { return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { - buh.Errors.Push(v2.ErrorCodeBlobUploadUnknown, err) + buh.Errors = append(buh.Errors, errcode.NewError(v2.ErrorCodeBlobUploadUnknown, err)) }) } return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { - buh.Errors.Push(errcode.ErrorCodeUnknown, err) + buh.Errors = append(buh.Errors, errcode.NewError(errcode.ErrorCodeUnknown, err)) }) } buh.Upload = upload @@ -81,14 +81,14 @@ func blobUploadDispatcher(ctx *Context, r *http.Request) http.Handler { defer upload.Close() ctxu.GetLogger(ctx).Infof("error seeking blob upload: %v", err) return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { - buh.Errors.Push(v2.ErrorCodeBlobUploadInvalid, err) + buh.Errors = append(buh.Errors, errcode.NewError(v2.ErrorCodeBlobUploadInvalid, err)) upload.Cancel(buh) }) } else if nn != buh.State.Offset { defer upload.Close() ctxu.GetLogger(ctx).Infof("seek to wrong offest: %d != %d", nn, buh.State.Offset) return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { - buh.Errors.Push(v2.ErrorCodeBlobUploadInvalid, err) + buh.Errors = append(buh.Errors, errcode.NewError(v2.ErrorCodeBlobUploadInvalid, err)) upload.Cancel(buh) }) } @@ -119,7 +119,7 @@ func (buh *blobUploadHandler) StartBlobUpload(w http.ResponseWriter, r *http.Req blobs := buh.Repository.Blobs(buh) upload, err := blobs.Create(buh) if err != nil { - buh.Errors.Push(errcode.ErrorCodeUnknown, err) + buh.Errors = append(buh.Errors, errcode.NewError(errcode.ErrorCodeUnknown, err)) return } @@ -127,7 +127,7 @@ func (buh *blobUploadHandler) StartBlobUpload(w http.ResponseWriter, r *http.Req defer buh.Upload.Close() if err := buh.blobUploadResponse(w, r, true); err != nil { - buh.Errors.Push(errcode.ErrorCodeUnknown, err) + buh.Errors = append(buh.Errors, errcode.NewError(errcode.ErrorCodeUnknown, err)) return } @@ -138,7 +138,7 @@ func (buh *blobUploadHandler) StartBlobUpload(w http.ResponseWriter, r *http.Req // GetUploadStatus returns the status of a given upload, identified by id. func (buh *blobUploadHandler) GetUploadStatus(w http.ResponseWriter, r *http.Request) { if buh.Upload == nil { - buh.Errors.Push(v2.ErrorCodeBlobUploadUnknown) + buh.Errors = append(buh.Errors, errcode.NewError(v2.ErrorCodeBlobUploadUnknown)) return } @@ -146,7 +146,7 @@ func (buh *blobUploadHandler) GetUploadStatus(w http.ResponseWriter, r *http.Req // resumable upload is supported. This will enable returning a non-zero // range for clients to begin uploading at an offset. if err := buh.blobUploadResponse(w, r, true); err != nil { - buh.Errors.Push(errcode.ErrorCodeUnknown, err) + buh.Errors = append(buh.Errors, errcode.NewError(errcode.ErrorCodeUnknown, err)) return } @@ -157,13 +157,13 @@ func (buh *blobUploadHandler) GetUploadStatus(w http.ResponseWriter, r *http.Req // PatchBlobData writes data to an upload. func (buh *blobUploadHandler) PatchBlobData(w http.ResponseWriter, r *http.Request) { if buh.Upload == nil { - buh.Errors.Push(v2.ErrorCodeBlobUploadUnknown) + buh.Errors = append(buh.Errors, errcode.NewError(v2.ErrorCodeBlobUploadUnknown)) return } ct := r.Header.Get("Content-Type") if ct != "" && ct != "application/octet-stream" { - buh.Errors.Push(errcode.ErrorCodeUnknown, fmt.Errorf("Bad Content-Type")) + buh.Errors = append(buh.Errors, errcode.NewError(errcode.ErrorCodeUnknown, fmt.Errorf("Bad Content-Type"))) // TODO(dmcgowan): encode error return } @@ -173,12 +173,12 @@ func (buh *blobUploadHandler) PatchBlobData(w http.ResponseWriter, r *http.Reque // Copy the data if _, err := io.Copy(buh.Upload, r.Body); err != nil { ctxu.GetLogger(buh).Errorf("unknown error copying into upload: %v", err) - buh.Errors.Push(errcode.ErrorCodeUnknown, err) + buh.Errors = append(buh.Errors, errcode.NewError(errcode.ErrorCodeUnknown, err)) return } if err := buh.blobUploadResponse(w, r, false); err != nil { - buh.Errors.Push(errcode.ErrorCodeUnknown, err) + buh.Errors = append(buh.Errors, errcode.NewError(errcode.ErrorCodeUnknown, err)) return } @@ -192,7 +192,7 @@ func (buh *blobUploadHandler) PatchBlobData(w http.ResponseWriter, r *http.Reque // url of the blob. func (buh *blobUploadHandler) PutBlobUploadComplete(w http.ResponseWriter, r *http.Request) { if buh.Upload == nil { - buh.Errors.Push(v2.ErrorCodeBlobUploadUnknown) + buh.Errors = append(buh.Errors, errcode.NewError(v2.ErrorCodeBlobUploadUnknown)) return } @@ -200,21 +200,21 @@ func (buh *blobUploadHandler) PutBlobUploadComplete(w http.ResponseWriter, r *ht if dgstStr == "" { // no digest? return error, but allow retry. - buh.Errors.Push(v2.ErrorCodeDigestInvalid, "digest missing") + buh.Errors = append(buh.Errors, errcode.NewError(v2.ErrorCodeDigestInvalid, "digest missing")) return } dgst, err := digest.ParseDigest(dgstStr) if err != nil { // no digest? return error, but allow retry. - buh.Errors.Push(v2.ErrorCodeDigestInvalid, "digest parsing failed") + buh.Errors = append(buh.Errors, errcode.NewError(v2.ErrorCodeDigestInvalid, "digest parsing failed")) return } // Read in the data, if any. if _, err := io.Copy(buh.Upload, r.Body); err != nil { ctxu.GetLogger(buh).Errorf("unknown error copying into upload: %v", err) - buh.Errors.Push(errcode.ErrorCodeUnknown, err) + buh.Errors = append(buh.Errors, errcode.NewError(errcode.ErrorCodeUnknown, err)) return } @@ -229,14 +229,14 @@ func (buh *blobUploadHandler) PutBlobUploadComplete(w http.ResponseWriter, r *ht if err != nil { switch err := err.(type) { case distribution.ErrBlobInvalidDigest: - buh.Errors.Push(v2.ErrorCodeDigestInvalid, err) + buh.Errors = append(buh.Errors, errcode.NewError(v2.ErrorCodeDigestInvalid, err)) default: switch err { case distribution.ErrBlobInvalidLength, distribution.ErrBlobDigestUnsupported: - buh.Errors.Push(v2.ErrorCodeBlobUploadInvalid, err) + buh.Errors = append(buh.Errors, errcode.NewError(v2.ErrorCodeBlobUploadInvalid, err)) default: ctxu.GetLogger(buh).Errorf("unknown error completing upload: %#v", err) - buh.Errors.Push(errcode.ErrorCodeUnknown, err) + buh.Errors = append(buh.Errors, errcode.NewError(errcode.ErrorCodeUnknown, err)) } } @@ -253,7 +253,7 @@ func (buh *blobUploadHandler) PutBlobUploadComplete(w http.ResponseWriter, r *ht // Build our canonical blob url blobURL, err := buh.urlBuilder.BuildBlobURL(buh.Repository.Name(), desc.Digest) if err != nil { - buh.Errors.Push(errcode.ErrorCodeUnknown, err) + buh.Errors = append(buh.Errors, errcode.NewError(errcode.ErrorCodeUnknown, err)) return } @@ -266,14 +266,14 @@ func (buh *blobUploadHandler) PutBlobUploadComplete(w http.ResponseWriter, r *ht // CancelBlobUpload cancels an in-progress upload of a blob. func (buh *blobUploadHandler) CancelBlobUpload(w http.ResponseWriter, r *http.Request) { if buh.Upload == nil { - buh.Errors.Push(v2.ErrorCodeBlobUploadUnknown) + buh.Errors = append(buh.Errors, errcode.NewError(v2.ErrorCodeBlobUploadUnknown)) return } w.Header().Set("Docker-Upload-UUID", buh.UUID) if err := buh.Upload.Cancel(buh); err != nil { ctxu.GetLogger(buh).Errorf("error encountered canceling upload: %v", err) - buh.Errors.PushErr(err) + buh.Errors = append(buh.Errors, errcode.NewError(errcode.ErrorCodeUnknown, err)) } w.WriteHeader(http.StatusNoContent) diff --git a/registry/handlers/helpers.go b/registry/handlers/helpers.go index 3611a72d9..f4f241751 100644 --- a/registry/handlers/helpers.go +++ b/registry/handlers/helpers.go @@ -14,8 +14,8 @@ func serveJSON(w http.ResponseWriter, v interface{}) error { w.Header().Set("Content-Type", "application/json; charset=utf-8") sc := http.StatusInternalServerError - if errs, ok := v.(errcode.Errors); ok && errs.Len() > 0 { - sc = errs.Errors[0].Code.Descriptor().HTTPStatusCode + if errs, ok := v.(errcode.Errors); ok && len(errs) > 0 { + sc = errs[0].Code.Descriptor().HTTPStatusCode if sc == 0 { sc = http.StatusInternalServerError } diff --git a/registry/handlers/images.go b/registry/handlers/images.go index d717cf724..9d025c787 100644 --- a/registry/handlers/images.go +++ b/registry/handlers/images.go @@ -10,6 +10,7 @@ import ( ctxu "github.com/docker/distribution/context" "github.com/docker/distribution/digest" "github.com/docker/distribution/manifest" + "github.com/docker/distribution/registry/api/errcode" "github.com/docker/distribution/registry/api/v2" "github.com/gorilla/handlers" "golang.org/x/net/context" @@ -63,7 +64,7 @@ func (imh *imageManifestHandler) GetImageManifest(w http.ResponseWriter, r *http } if err != nil { - imh.Errors.Push(v2.ErrorCodeManifestUnknown, err) + imh.Errors = append(imh.Errors, errcode.NewError(v2.ErrorCodeManifestUnknown, err)) return } @@ -71,7 +72,7 @@ func (imh *imageManifestHandler) GetImageManifest(w http.ResponseWriter, r *http if imh.Digest == "" { dgst, err := digestManifest(imh, sm) if err != nil { - imh.Errors.Push(v2.ErrorCodeDigestInvalid, err) + imh.Errors = append(imh.Errors, errcode.NewError(v2.ErrorCodeDigestInvalid, err)) return } @@ -92,13 +93,13 @@ func (imh *imageManifestHandler) PutImageManifest(w http.ResponseWriter, r *http var manifest manifest.SignedManifest if err := dec.Decode(&manifest); err != nil { - imh.Errors.Push(v2.ErrorCodeManifestInvalid, err) + imh.Errors = append(imh.Errors, errcode.NewError(v2.ErrorCodeManifestInvalid, err)) return } dgst, err := digestManifest(imh, &manifest) if err != nil { - imh.Errors.Push(v2.ErrorCodeDigestInvalid, err) + imh.Errors = append(imh.Errors, errcode.NewError(v2.ErrorCodeDigestInvalid, err)) return } @@ -106,7 +107,7 @@ func (imh *imageManifestHandler) PutImageManifest(w http.ResponseWriter, r *http if imh.Tag != "" { if manifest.Tag != imh.Tag { ctxu.GetLogger(imh).Errorf("invalid tag on manifest payload: %q != %q", manifest.Tag, imh.Tag) - imh.Errors.Push(v2.ErrorCodeTagInvalid) + imh.Errors = append(imh.Errors, errcode.NewError(v2.ErrorCodeTagInvalid)) return } @@ -114,11 +115,11 @@ func (imh *imageManifestHandler) PutImageManifest(w http.ResponseWriter, r *http } else if imh.Digest != "" { if dgst != imh.Digest { ctxu.GetLogger(imh).Errorf("payload digest does match: %q != %q", dgst, imh.Digest) - imh.Errors.Push(v2.ErrorCodeDigestInvalid) + imh.Errors = append(imh.Errors, errcode.NewError(v2.ErrorCodeDigestInvalid)) return } } else { - imh.Errors.Push(v2.ErrorCodeTagInvalid, "no tag or digest specified") + imh.Errors = append(imh.Errors, errcode.NewError(v2.ErrorCodeTagInvalid, "no tag or digest specified")) return } @@ -130,19 +131,19 @@ func (imh *imageManifestHandler) PutImageManifest(w http.ResponseWriter, r *http for _, verificationError := range err { switch verificationError := verificationError.(type) { case distribution.ErrManifestBlobUnknown: - imh.Errors.Push(v2.ErrorCodeBlobUnknown, verificationError.Digest) + imh.Errors = append(imh.Errors, errcode.NewError(v2.ErrorCodeBlobUnknown, verificationError.Digest)) case distribution.ErrManifestUnverified: - imh.Errors.Push(v2.ErrorCodeManifestUnverified) + imh.Errors = append(imh.Errors, errcode.NewError(v2.ErrorCodeManifestUnverified)) default: if verificationError == digest.ErrDigestInvalidFormat { - imh.Errors.Push(v2.ErrorCodeDigestInvalid) + imh.Errors = append(imh.Errors, errcode.NewError(v2.ErrorCodeDigestInvalid)) } else { - imh.Errors.PushErr(verificationError) + imh.Errors = append(imh.Errors, errcode.NewError(errcode.ErrorCodeUnknown, verificationError)) } } } default: - imh.Errors.PushErr(err) + imh.Errors = append(imh.Errors, errcode.NewError(errcode.ErrorCodeUnknown, err)) } return @@ -171,7 +172,7 @@ func (imh *imageManifestHandler) DeleteImageManifest(w http.ResponseWriter, r *h // tag index entries a serious problem in eventually consistent storage. // Once we work out schema version 2, the full deletion system will be // worked out and we can add support back. - imh.Errors.Push(v2.ErrorCodeUnsupported) + imh.Errors = append(imh.Errors, errcode.NewError(v2.ErrorCodeUnsupported)) } // digestManifest takes a digest of the given manifest. This belongs somewhere diff --git a/registry/handlers/tags.go b/registry/handlers/tags.go index 44b12dfdb..e1846cf96 100644 --- a/registry/handlers/tags.go +++ b/registry/handlers/tags.go @@ -5,6 +5,7 @@ import ( "net/http" "github.com/docker/distribution" + "github.com/docker/distribution/registry/api/errcode" "github.com/docker/distribution/registry/api/v2" "github.com/gorilla/handlers" ) @@ -39,9 +40,9 @@ func (th *tagsHandler) GetTags(w http.ResponseWriter, r *http.Request) { if err != nil { switch err := err.(type) { case distribution.ErrRepositoryUnknown: - th.Errors.Push(v2.ErrorCodeNameUnknown, map[string]string{"name": th.Repository.Name()}) + th.Errors = append(th.Errors, errcode.NewError(v2.ErrorCodeNameUnknown, map[string]string{"name": th.Repository.Name()})) default: - th.Errors.PushErr(err) + th.Errors = append(th.Errors, errcode.NewError(errcode.ErrorCodeUnknown, err)) } return } @@ -53,7 +54,7 @@ func (th *tagsHandler) GetTags(w http.ResponseWriter, r *http.Request) { Name: th.Repository.Name(), Tags: tags, }); err != nil { - th.Errors.PushErr(err) + th.Errors = append(th.Errors, errcode.NewError(errcode.ErrorCodeUnknown, err)) return } }