Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
66 changes: 34 additions & 32 deletions routers/api/packages/container/container.go
Original file line number Diff line number Diff line change
Expand Up @@ -101,6 +101,7 @@ func apiErrorDefined(ctx *context.Context, err *namedError) {
type ContainerError struct {
Code string `json:"code"`
Message string `json:"message"`
Detail any `json:"detail,omitempty"`
}

type ContainerErrors struct {
Expand All @@ -112,6 +113,7 @@ func apiErrorDefined(ctx *context.Context, err *namedError) {
{
Code: err.Code,
Message: err.Message,
Detail: err.Detail,
},
},
})
Expand Down Expand Up @@ -174,7 +176,7 @@ func Authenticate(ctx *context.Context) {

token, err := packages_service.CreateAuthorizationToken(u, packageScope)
if err != nil {
apiError(ctx, http.StatusInternalServerError, err)
apiErrorDefined(ctx, errUnsupported.WithDetail(err))
return
}

Expand Down Expand Up @@ -204,7 +206,7 @@ func GetRepositoryList(ctx *context.Context) {

repositories, err := container_model.GetRepositories(ctx, ctx.Doer, n, last)
if err != nil {
apiError(ctx, http.StatusInternalServerError, err)
apiErrorDefined(ctx, errUnsupported.WithDetail(err))
return
}

Expand Down Expand Up @@ -243,13 +245,13 @@ func InitiateUploadBlob(ctx *context.Context) {
if blob != nil {
accessible, err := packages_model.IsBlobAccessibleForUser(ctx, blob.Blob.ID, ctx.Doer)
if err != nil {
apiError(ctx, http.StatusInternalServerError, err)
apiErrorDefined(ctx, errUnsupported.WithDetail(err))
return
}

if accessible {
if err := mountBlob(ctx, &packages_service.PackageInfo{Owner: ctx.Package.Owner, Name: image}, blob.Blob); err != nil {
apiError(ctx, http.StatusInternalServerError, err)
apiErrorDefined(ctx, errUnsupported.WithDetail(err))
return
}

Expand All @@ -267,7 +269,7 @@ func InitiateUploadBlob(ctx *context.Context) {
if digest != "" {
buf, err := packages_module.CreateHashedBufferFromReader(ctx.Req.Body)
if err != nil {
apiError(ctx, http.StatusInternalServerError, err)
apiErrorDefined(ctx, errUnsupported.WithDetail(err))
return
}
defer buf.Close()
Expand All @@ -291,7 +293,7 @@ func InitiateUploadBlob(ctx *context.Context) {
case packages_service.ErrQuotaTotalCount, packages_service.ErrQuotaTypeSize, packages_service.ErrQuotaTotalSize:
apiError(ctx, http.StatusForbidden, err)
default:
apiError(ctx, http.StatusInternalServerError, err)
apiErrorDefined(ctx, errUnsupported.WithDetail(err))
}
return
}
Expand All @@ -306,7 +308,7 @@ func InitiateUploadBlob(ctx *context.Context) {

upload, err := packages_model.CreateBlobUpload(ctx)
if err != nil {
apiError(ctx, http.StatusInternalServerError, err)
apiErrorDefined(ctx, errUnsupported.WithDetail(err))
return
}

Expand All @@ -327,7 +329,7 @@ func GetUploadBlob(ctx *context.Context) {
if err == packages_model.ErrPackageBlobUploadNotExist {
apiErrorDefined(ctx, errBlobUploadUnknown)
} else {
apiError(ctx, http.StatusInternalServerError, err)
apiErrorDefined(ctx, errUnsupported.WithDetail(err))
}
return
}
Expand All @@ -348,7 +350,7 @@ func UploadBlob(ctx *context.Context) {
if err == packages_model.ErrPackageBlobUploadNotExist {
apiErrorDefined(ctx, errBlobUploadUnknown)
} else {
apiError(ctx, http.StatusInternalServerError, err)
apiErrorDefined(ctx, errUnsupported.WithDetail(err))
}
return
}
Expand All @@ -367,12 +369,12 @@ func UploadBlob(ctx *context.Context) {
return
}
} else if uploader.Size() != 0 {
apiErrorDefined(ctx, errBlobUploadInvalid.WithMessage("Stream uploads after first write are not allowed"))
apiErrorDefined(ctx, errBlobUploadInvalid.WithDetail("Stream uploads after first write are not allowed"))
return
}

if err := uploader.Append(ctx, ctx.Req.Body); err != nil {
apiError(ctx, http.StatusInternalServerError, err)
apiErrorDefined(ctx, errUnsupported.WithDetail(err))
return
}

Expand All @@ -399,7 +401,7 @@ func EndUploadBlob(ctx *context.Context) {
if err == packages_model.ErrPackageBlobUploadNotExist {
apiErrorDefined(ctx, errBlobUploadUnknown)
} else {
apiError(ctx, http.StatusInternalServerError, err)
apiErrorDefined(ctx, errUnsupported.WithDetail(err))
}
return
}
Expand All @@ -412,7 +414,7 @@ func EndUploadBlob(ctx *context.Context) {

if ctx.Req.Body != nil {
if err := uploader.Append(ctx, ctx.Req.Body); err != nil {
apiError(ctx, http.StatusInternalServerError, err)
apiErrorDefined(ctx, errUnsupported.WithDetail(err))
return
}
}
Expand All @@ -436,19 +438,19 @@ func EndUploadBlob(ctx *context.Context) {
case packages_service.ErrQuotaTotalCount, packages_service.ErrQuotaTypeSize, packages_service.ErrQuotaTotalSize:
apiError(ctx, http.StatusForbidden, err)
default:
apiError(ctx, http.StatusInternalServerError, err)
apiErrorDefined(ctx, errUnsupported.WithDetail(err))
}
return
}

if err := uploader.Close(); err != nil {
apiError(ctx, http.StatusInternalServerError, err)
apiErrorDefined(ctx, errUnsupported.WithDetail(err))
return
}
doClose = false

if err := container_service.RemoveBlobUploadByID(ctx, uploader.ID); err != nil {
apiError(ctx, http.StatusInternalServerError, err)
apiErrorDefined(ctx, errUnsupported.WithDetail(err))
return
}

Expand All @@ -468,13 +470,13 @@ func CancelUploadBlob(ctx *context.Context) {
if err == packages_model.ErrPackageBlobUploadNotExist {
apiErrorDefined(ctx, errBlobUploadUnknown)
} else {
apiError(ctx, http.StatusInternalServerError, err)
apiErrorDefined(ctx, errUnsupported.WithDetail(err))
}
return
}

if err := container_service.RemoveBlobUploadByID(ctx, uuid); err != nil {
apiError(ctx, http.StatusInternalServerError, err)
apiErrorDefined(ctx, errUnsupported.WithDetail(err))
return
}

Expand Down Expand Up @@ -504,7 +506,7 @@ func HeadBlob(ctx *context.Context) {
if err == container_model.ErrContainerBlobNotExist {
apiErrorDefined(ctx, errBlobUnknown)
} else {
apiError(ctx, http.StatusInternalServerError, err)
apiErrorDefined(ctx, errUnsupported.WithDetail(err))
}
return
}
Expand All @@ -523,7 +525,7 @@ func GetBlob(ctx *context.Context) {
if err == container_model.ErrContainerBlobNotExist {
apiErrorDefined(ctx, errBlobUnknown)
} else {
apiError(ctx, http.StatusInternalServerError, err)
apiErrorDefined(ctx, errUnsupported.WithDetail(err))
}
return
}
Expand All @@ -541,7 +543,7 @@ func DeleteBlob(ctx *context.Context) {
}

if err := deleteBlob(ctx, ctx.Package.Owner.ID, ctx.PathParam("image"), d); err != nil {
apiError(ctx, http.StatusInternalServerError, err)
apiErrorDefined(ctx, errUnsupported.WithDetail(err))
return
}

Expand All @@ -564,20 +566,20 @@ func UploadManifest(ctx *context.Context) {
}

if mci.IsTagged && !referencePattern.MatchString(reference) {
apiErrorDefined(ctx, errManifestInvalid.WithMessage("Tag is invalid"))
apiErrorDefined(ctx, errTagInvalid)
return
}

maxSize := maxManifestSize + 1
buf, err := packages_module.CreateHashedBufferFromReaderWithSize(&io.LimitedReader{R: ctx.Req.Body, N: int64(maxSize)}, maxSize)
if err != nil {
apiError(ctx, http.StatusInternalServerError, err)
apiErrorDefined(ctx, errUnsupported.WithDetail(err))
return
}
defer buf.Close()

if buf.Size() > maxManifestSize {
apiErrorDefined(ctx, errManifestInvalid.WithMessage("Manifest exceeds maximum size").WithStatusCode(http.StatusRequestEntityTooLarge))
apiErrorDefined(ctx, errManifestInvalid.WithDetail("Manifest exceeds maximum size").WithStatusCode(http.StatusRequestEntityTooLarge))
return
}

Expand All @@ -593,7 +595,7 @@ func UploadManifest(ctx *context.Context) {
case packages_service.ErrQuotaTotalCount, packages_service.ErrQuotaTypeSize, packages_service.ErrQuotaTotalSize:
apiError(ctx, http.StatusForbidden, err)
default:
apiError(ctx, http.StatusInternalServerError, err)
apiErrorDefined(ctx, errUnsupported.WithDetail(err))
}
}
return
Expand Down Expand Up @@ -642,7 +644,7 @@ func HeadManifest(ctx *context.Context) {
if err == container_model.ErrContainerBlobNotExist {
apiErrorDefined(ctx, errManifestUnknown)
} else {
apiError(ctx, http.StatusInternalServerError, err)
apiErrorDefined(ctx, errUnsupported.WithDetail(err))
}
return
}
Expand All @@ -662,7 +664,7 @@ func GetManifest(ctx *context.Context) {
if err == container_model.ErrContainerBlobNotExist {
apiErrorDefined(ctx, errManifestUnknown)
} else {
apiError(ctx, http.StatusInternalServerError, err)
apiErrorDefined(ctx, errUnsupported.WithDetail(err))
}
return
}
Expand All @@ -681,7 +683,7 @@ func DeleteManifest(ctx *context.Context) {

pvs, err := container_model.GetManifestVersions(ctx, opts)
if err != nil {
apiError(ctx, http.StatusInternalServerError, err)
apiErrorDefined(ctx, errUnsupported.WithDetail(err))
return
}

Expand All @@ -692,7 +694,7 @@ func DeleteManifest(ctx *context.Context) {

for _, pv := range pvs {
if err := packages_service.RemovePackageVersion(ctx, ctx.Doer, pv); err != nil {
apiError(ctx, http.StatusInternalServerError, err)
apiErrorDefined(ctx, errUnsupported.WithDetail(err))
return
}
}
Expand All @@ -707,7 +709,7 @@ func serveBlob(ctx *context.Context, pfd *packages_model.PackageFileDescriptor)
serveDirectReqParams.Set("response-content-type", pfd.Properties.GetByName(container_module.PropertyMediaType))
s, u, _, err := packages_service.GetPackageBlobStream(ctx, pfd.File, pfd.Blob, serveDirectReqParams)
if err != nil {
apiError(ctx, http.StatusInternalServerError, err)
apiErrorDefined(ctx, errUnsupported.WithDetail(err))
return
}

Expand Down Expand Up @@ -742,7 +744,7 @@ func GetTagList(ctx *context.Context) {
if err == packages_model.ErrPackageNotExist {
apiErrorDefined(ctx, errNameUnknown)
} else {
apiError(ctx, http.StatusInternalServerError, err)
apiErrorDefined(ctx, errUnsupported.WithDetail(err))
}
return
}
Expand All @@ -755,7 +757,7 @@ func GetTagList(ctx *context.Context) {

tags, err := container_model.GetImageTags(ctx, ctx.Package.Owner.ID, image, n, last)
if err != nil {
apiError(ctx, http.StatusInternalServerError, err)
apiErrorDefined(ctx, errUnsupported.WithDetail(err))
return
}

Expand Down
40 changes: 28 additions & 12 deletions routers/api/packages/container/errors.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,24 +9,30 @@ import (

// https://github.com/opencontainers/distribution-spec/blob/main/spec.md#error-codes
var (
errBlobUnknown = &namedError{Code: "BLOB_UNKNOWN", StatusCode: http.StatusNotFound}
errBlobUploadInvalid = &namedError{Code: "BLOB_UPLOAD_INVALID", StatusCode: http.StatusBadRequest}
errBlobUploadUnknown = &namedError{Code: "BLOB_UPLOAD_UNKNOWN", StatusCode: http.StatusNotFound}
errDigestInvalid = &namedError{Code: "DIGEST_INVALID", StatusCode: http.StatusBadRequest}
errManifestBlobUnknown = &namedError{Code: "MANIFEST_BLOB_UNKNOWN", StatusCode: http.StatusNotFound}
errManifestInvalid = &namedError{Code: "MANIFEST_INVALID", StatusCode: http.StatusBadRequest}
errManifestUnknown = &namedError{Code: "MANIFEST_UNKNOWN", StatusCode: http.StatusNotFound}
errNameInvalid = &namedError{Code: "NAME_INVALID", StatusCode: http.StatusBadRequest}
errNameUnknown = &namedError{Code: "NAME_UNKNOWN", StatusCode: http.StatusNotFound}
errSizeInvalid = &namedError{Code: "SIZE_INVALID", StatusCode: http.StatusBadRequest}
errUnauthorized = &namedError{Code: "UNAUTHORIZED", StatusCode: http.StatusUnauthorized}
errUnsupported = &namedError{Code: "UNSUPPORTED", StatusCode: http.StatusNotImplemented}
errBlobUnknown = &namedError{Code: "BLOB_UNKNOWN", StatusCode: http.StatusNotFound, Message: "blob unknown to registry"}
errBlobUploadInvalid = &namedError{Code: "BLOB_UPLOAD_INVALID", StatusCode: http.StatusBadRequest, Message: "blob upload invalid"}
errBlobUploadUnknown = &namedError{Code: "BLOB_UPLOAD_UNKNOWN", StatusCode: http.StatusNotFound, Message: "blob upload unknown to registry"}
errDigestInvalid = &namedError{Code: "DIGEST_INVALID", StatusCode: http.StatusBadRequest, Message: "provided digest did not match uploaded content"}
errManifestBlobUnknown = &namedError{Code: "MANIFEST_BLOB_UNKNOWN", StatusCode: http.StatusNotFound, Message: "blob unknown to registry"}
errManifestInvalid = &namedError{Code: "MANIFEST_INVALID", StatusCode: http.StatusBadRequest, Message: "manifest invalid"}
errManifestUnknown = &namedError{Code: "MANIFEST_UNKNOWN", StatusCode: http.StatusNotFound, Message: "manifest unknown"}
errManifestUnverified = &namedError{Code: "MANIFEST_UNVERIFIED", StatusCode: http.StatusBadRequest, Message: "manifest failed signature verification"} //nolint:unused
errNameInvalid = &namedError{Code: "NAME_INVALID", StatusCode: http.StatusBadRequest, Message: "invalid repository name"}
errNameUnknown = &namedError{Code: "NAME_UNKNOWN", StatusCode: http.StatusNotFound, Message: "repository name not known to registry"}
errPaginationNumberInvalid = &namedError{Code: "PAGINATION_NUMBER_INVALID", StatusCode: http.StatusBadRequest, Message: "invalid number of results requested"} //nolint:unused
errRangeInvalid = &namedError{Code: "RANGE_INVALID", StatusCode: http.StatusBadRequest, Message: "invalid content range"} //nolint:unused
errSizeInvalid = &namedError{Code: "SIZE_INVALID", StatusCode: http.StatusBadRequest, Message: "provided length did not match content length"}
errTagInvalid = &namedError{Code: "TAG_INVALID", StatusCode: http.StatusBadRequest, Message: "manifest tag did not match URI"}
errUnauthorized = &namedError{Code: "UNAUTHORIZED", StatusCode: http.StatusUnauthorized, Message: "authentication required"}
errDenied = &namedError{Code: "DENIED", StatusCode: http.StatusForbidden, Message: "requested access to the resource is denied"} //nolint:unused
errUnsupported = &namedError{Code: "UNSUPPORTED", StatusCode: http.StatusMethodNotAllowed, Message: "The operation is unsupported"}
)

type namedError struct {
Code string
StatusCode int
Message string
Detail any
}

func (e *namedError) Error() string {
Expand All @@ -50,3 +56,13 @@ func (e *namedError) WithStatusCode(statusCode int) *namedError {
Message: e.Message,
}
}

// WithDetail creates a new instance of the error with detail
func (e *namedError) WithDetail(detail any) *namedError {
return &namedError{
Code: e.Code,
StatusCode: e.StatusCode,
Message: e.Message,
Detail: detail,
}
}
4 changes: 2 additions & 2 deletions routers/api/packages/container/manifest.go
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,7 @@ func processManifest(ctx context.Context, mci *manifestCreationInfo, buf *packag
}

if index.SchemaVersion != 2 {
return "", errUnsupported.WithMessage("Schema version is not supported")
return "", errUnsupported.WithDetail("Schema version is not supported")
}

if _, err := buf.Seek(0, io.SeekStart); err != nil {
Expand All @@ -67,7 +67,7 @@ func processManifest(ctx context.Context, mci *manifestCreationInfo, buf *packag
if !isValidMediaType(mci.MediaType) {
mci.MediaType = index.MediaType
if !isValidMediaType(mci.MediaType) {
return "", errManifestInvalid.WithMessage("MediaType not recognized")
return "", errManifestInvalid.WithDetail("MediaType not recognized")
}
}

Expand Down
Loading