Skip to content

Commit 92c5c37

Browse files
committed
Optimize docker registry response code
1 parent d45456b commit 92c5c37

File tree

3 files changed

+66
-48
lines changed

3 files changed

+66
-48
lines changed

routers/api/packages/container/container.go

Lines changed: 36 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -99,8 +99,9 @@ func apiError(ctx *context.Context, status int, err error) {
9999
// https://github.com/opencontainers/distribution-spec/blob/main/spec.md#error-codes
100100
func apiErrorDefined(ctx *context.Context, err *namedError) {
101101
type ContainerError struct {
102-
Code string `json:"code"`
103-
Message string `json:"message"`
102+
Code string `json:"code"`
103+
Message string `json:"message"`
104+
Detail interface{} `json:"detail,omitempty"`
104105
}
105106

106107
type ContainerErrors struct {
@@ -112,6 +113,7 @@ func apiErrorDefined(ctx *context.Context, err *namedError) {
112113
{
113114
Code: err.Code,
114115
Message: err.Message,
116+
Detail: err.Detail,
115117
},
116118
},
117119
})
@@ -174,7 +176,7 @@ func Authenticate(ctx *context.Context) {
174176

175177
token, err := packages_service.CreateAuthorizationToken(u, packageScope)
176178
if err != nil {
177-
apiError(ctx, http.StatusInternalServerError, err)
179+
apiErrorDefined(ctx, errUnsupported.WithDetail(err))
178180
return
179181
}
180182

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

205207
repositories, err := container_model.GetRepositories(ctx, ctx.Doer, n, last)
206208
if err != nil {
207-
apiError(ctx, http.StatusInternalServerError, err)
209+
apiErrorDefined(ctx, errUnsupported.WithDetail(err))
208210
return
209211
}
210212

@@ -243,13 +245,13 @@ func InitiateUploadBlob(ctx *context.Context) {
243245
if blob != nil {
244246
accessible, err := packages_model.IsBlobAccessibleForUser(ctx, blob.Blob.ID, ctx.Doer)
245247
if err != nil {
246-
apiError(ctx, http.StatusInternalServerError, err)
248+
apiErrorDefined(ctx, errUnsupported.WithDetail(err))
247249
return
248250
}
249251

250252
if accessible {
251253
if err := mountBlob(ctx, &packages_service.PackageInfo{Owner: ctx.Package.Owner, Name: image}, blob.Blob); err != nil {
252-
apiError(ctx, http.StatusInternalServerError, err)
254+
apiErrorDefined(ctx, errUnsupported.WithDetail(err))
253255
return
254256
}
255257

@@ -267,7 +269,7 @@ func InitiateUploadBlob(ctx *context.Context) {
267269
if digest != "" {
268270
buf, err := packages_module.CreateHashedBufferFromReader(ctx.Req.Body)
269271
if err != nil {
270-
apiError(ctx, http.StatusInternalServerError, err)
272+
apiErrorDefined(ctx, errUnsupported.WithDetail(err))
271273
return
272274
}
273275
defer buf.Close()
@@ -291,7 +293,7 @@ func InitiateUploadBlob(ctx *context.Context) {
291293
case packages_service.ErrQuotaTotalCount, packages_service.ErrQuotaTypeSize, packages_service.ErrQuotaTotalSize:
292294
apiError(ctx, http.StatusForbidden, err)
293295
default:
294-
apiError(ctx, http.StatusInternalServerError, err)
296+
apiErrorDefined(ctx, errUnsupported.WithDetail(err))
295297
}
296298
return
297299
}
@@ -306,7 +308,7 @@ func InitiateUploadBlob(ctx *context.Context) {
306308

307309
upload, err := packages_model.CreateBlobUpload(ctx)
308310
if err != nil {
309-
apiError(ctx, http.StatusInternalServerError, err)
311+
apiErrorDefined(ctx, errUnsupported.WithDetail(err))
310312
return
311313
}
312314

@@ -327,7 +329,7 @@ func GetUploadBlob(ctx *context.Context) {
327329
if err == packages_model.ErrPackageBlobUploadNotExist {
328330
apiErrorDefined(ctx, errBlobUploadUnknown)
329331
} else {
330-
apiError(ctx, http.StatusInternalServerError, err)
332+
apiErrorDefined(ctx, errUnsupported.WithDetail(err))
331333
}
332334
return
333335
}
@@ -348,7 +350,7 @@ func UploadBlob(ctx *context.Context) {
348350
if err == packages_model.ErrPackageBlobUploadNotExist {
349351
apiErrorDefined(ctx, errBlobUploadUnknown)
350352
} else {
351-
apiError(ctx, http.StatusInternalServerError, err)
353+
apiErrorDefined(ctx, errUnsupported.WithDetail(err))
352354
}
353355
return
354356
}
@@ -367,12 +369,12 @@ func UploadBlob(ctx *context.Context) {
367369
return
368370
}
369371
} else if uploader.Size() != 0 {
370-
apiErrorDefined(ctx, errBlobUploadInvalid.WithMessage("Stream uploads after first write are not allowed"))
372+
apiErrorDefined(ctx, errBlobUploadInvalid.WithDetail("Stream uploads after first write are not allowed"))
371373
return
372374
}
373375

374376
if err := uploader.Append(ctx, ctx.Req.Body); err != nil {
375-
apiError(ctx, http.StatusInternalServerError, err)
377+
apiErrorDefined(ctx, errUnsupported.WithDetail(err))
376378
return
377379
}
378380

@@ -399,7 +401,7 @@ func EndUploadBlob(ctx *context.Context) {
399401
if err == packages_model.ErrPackageBlobUploadNotExist {
400402
apiErrorDefined(ctx, errBlobUploadUnknown)
401403
} else {
402-
apiError(ctx, http.StatusInternalServerError, err)
404+
apiErrorDefined(ctx, errUnsupported.WithDetail(err))
403405
}
404406
return
405407
}
@@ -412,7 +414,7 @@ func EndUploadBlob(ctx *context.Context) {
412414

413415
if ctx.Req.Body != nil {
414416
if err := uploader.Append(ctx, ctx.Req.Body); err != nil {
415-
apiError(ctx, http.StatusInternalServerError, err)
417+
apiErrorDefined(ctx, errUnsupported.WithDetail(err))
416418
return
417419
}
418420
}
@@ -436,19 +438,19 @@ func EndUploadBlob(ctx *context.Context) {
436438
case packages_service.ErrQuotaTotalCount, packages_service.ErrQuotaTypeSize, packages_service.ErrQuotaTotalSize:
437439
apiError(ctx, http.StatusForbidden, err)
438440
default:
439-
apiError(ctx, http.StatusInternalServerError, err)
441+
apiErrorDefined(ctx, errUnsupported.WithDetail(err))
440442
}
441443
return
442444
}
443445

444446
if err := uploader.Close(); err != nil {
445-
apiError(ctx, http.StatusInternalServerError, err)
447+
apiErrorDefined(ctx, errUnsupported.WithDetail(err))
446448
return
447449
}
448450
doClose = false
449451

450452
if err := container_service.RemoveBlobUploadByID(ctx, uploader.ID); err != nil {
451-
apiError(ctx, http.StatusInternalServerError, err)
453+
apiErrorDefined(ctx, errUnsupported.WithDetail(err))
452454
return
453455
}
454456

@@ -468,13 +470,13 @@ func CancelUploadBlob(ctx *context.Context) {
468470
if err == packages_model.ErrPackageBlobUploadNotExist {
469471
apiErrorDefined(ctx, errBlobUploadUnknown)
470472
} else {
471-
apiError(ctx, http.StatusInternalServerError, err)
473+
apiErrorDefined(ctx, errUnsupported.WithDetail(err))
472474
}
473475
return
474476
}
475477

476478
if err := container_service.RemoveBlobUploadByID(ctx, uuid); err != nil {
477-
apiError(ctx, http.StatusInternalServerError, err)
479+
apiErrorDefined(ctx, errUnsupported.WithDetail(err))
478480
return
479481
}
480482

@@ -504,7 +506,7 @@ func HeadBlob(ctx *context.Context) {
504506
if err == container_model.ErrContainerBlobNotExist {
505507
apiErrorDefined(ctx, errBlobUnknown)
506508
} else {
507-
apiError(ctx, http.StatusInternalServerError, err)
509+
apiErrorDefined(ctx, errUnsupported.WithDetail(err))
508510
}
509511
return
510512
}
@@ -523,7 +525,7 @@ func GetBlob(ctx *context.Context) {
523525
if err == container_model.ErrContainerBlobNotExist {
524526
apiErrorDefined(ctx, errBlobUnknown)
525527
} else {
526-
apiError(ctx, http.StatusInternalServerError, err)
528+
apiErrorDefined(ctx, errUnsupported.WithDetail(err))
527529
}
528530
return
529531
}
@@ -541,7 +543,7 @@ func DeleteBlob(ctx *context.Context) {
541543
}
542544

543545
if err := deleteBlob(ctx, ctx.Package.Owner.ID, ctx.PathParam("image"), d); err != nil {
544-
apiError(ctx, http.StatusInternalServerError, err)
546+
apiErrorDefined(ctx, errUnsupported.WithDetail(err))
545547
return
546548
}
547549

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

566568
if mci.IsTagged && !referencePattern.MatchString(reference) {
567-
apiErrorDefined(ctx, errManifestInvalid.WithMessage("Tag is invalid"))
569+
apiErrorDefined(ctx, errTagInvalid)
568570
return
569571
}
570572

571573
maxSize := maxManifestSize + 1
572574
buf, err := packages_module.CreateHashedBufferFromReaderWithSize(&io.LimitedReader{R: ctx.Req.Body, N: int64(maxSize)}, maxSize)
573575
if err != nil {
574-
apiError(ctx, http.StatusInternalServerError, err)
576+
apiErrorDefined(ctx, errUnsupported.WithDetail(err))
575577
return
576578
}
577579
defer buf.Close()
578580

579581
if buf.Size() > maxManifestSize {
580-
apiErrorDefined(ctx, errManifestInvalid.WithMessage("Manifest exceeds maximum size").WithStatusCode(http.StatusRequestEntityTooLarge))
582+
apiErrorDefined(ctx, errManifestInvalid.WithDetail("Manifest exceeds maximum size").WithStatusCode(http.StatusRequestEntityTooLarge))
581583
return
582584
}
583585

@@ -593,7 +595,7 @@ func UploadManifest(ctx *context.Context) {
593595
case packages_service.ErrQuotaTotalCount, packages_service.ErrQuotaTypeSize, packages_service.ErrQuotaTotalSize:
594596
apiError(ctx, http.StatusForbidden, err)
595597
default:
596-
apiError(ctx, http.StatusInternalServerError, err)
598+
apiErrorDefined(ctx, errUnsupported.WithDetail(err))
597599
}
598600
}
599601
return
@@ -642,7 +644,7 @@ func HeadManifest(ctx *context.Context) {
642644
if err == container_model.ErrContainerBlobNotExist {
643645
apiErrorDefined(ctx, errManifestUnknown)
644646
} else {
645-
apiError(ctx, http.StatusInternalServerError, err)
647+
apiErrorDefined(ctx, errUnsupported.WithDetail(err))
646648
}
647649
return
648650
}
@@ -662,7 +664,7 @@ func GetManifest(ctx *context.Context) {
662664
if err == container_model.ErrContainerBlobNotExist {
663665
apiErrorDefined(ctx, errManifestUnknown)
664666
} else {
665-
apiError(ctx, http.StatusInternalServerError, err)
667+
apiErrorDefined(ctx, errUnsupported.WithDetail(err))
666668
}
667669
return
668670
}
@@ -681,7 +683,7 @@ func DeleteManifest(ctx *context.Context) {
681683

682684
pvs, err := container_model.GetManifestVersions(ctx, opts)
683685
if err != nil {
684-
apiError(ctx, http.StatusInternalServerError, err)
686+
apiErrorDefined(ctx, errUnsupported.WithDetail(err))
685687
return
686688
}
687689

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

693695
for _, pv := range pvs {
694696
if err := packages_service.RemovePackageVersion(ctx, ctx.Doer, pv); err != nil {
695-
apiError(ctx, http.StatusInternalServerError, err)
697+
apiErrorDefined(ctx, errUnsupported.WithDetail(err))
696698
return
697699
}
698700
}
@@ -707,7 +709,7 @@ func serveBlob(ctx *context.Context, pfd *packages_model.PackageFileDescriptor)
707709
serveDirectReqParams.Set("response-content-type", pfd.Properties.GetByName(container_module.PropertyMediaType))
708710
s, u, _, err := packages_service.GetPackageBlobStream(ctx, pfd.File, pfd.Blob, serveDirectReqParams)
709711
if err != nil {
710-
apiError(ctx, http.StatusInternalServerError, err)
712+
apiErrorDefined(ctx, errUnsupported.WithDetail(err))
711713
return
712714
}
713715

@@ -742,7 +744,7 @@ func GetTagList(ctx *context.Context) {
742744
if err == packages_model.ErrPackageNotExist {
743745
apiErrorDefined(ctx, errNameUnknown)
744746
} else {
745-
apiError(ctx, http.StatusInternalServerError, err)
747+
apiErrorDefined(ctx, errUnsupported.WithDetail(err))
746748
}
747749
return
748750
}
@@ -755,7 +757,7 @@ func GetTagList(ctx *context.Context) {
755757

756758
tags, err := container_model.GetImageTags(ctx, ctx.Package.Owner.ID, image, n, last)
757759
if err != nil {
758-
apiError(ctx, http.StatusInternalServerError, err)
760+
apiErrorDefined(ctx, errUnsupported.WithDetail(err))
759761
return
760762
}
761763

routers/api/packages/container/errors.go

Lines changed: 28 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -9,24 +9,30 @@ import (
99

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

2631
type namedError struct {
2732
Code string
2833
StatusCode int
2934
Message string
35+
Detail interface{}
3036
}
3137

3238
func (e *namedError) Error() string {
@@ -50,3 +56,13 @@ func (e *namedError) WithStatusCode(statusCode int) *namedError {
5056
Message: e.Message,
5157
}
5258
}
59+
60+
// WithDetail creates a new instance of the error with detail
61+
func (e *namedError) WithDetail(detail interface{}) *namedError {
62+
return &namedError{
63+
Code: e.Code,
64+
StatusCode: e.StatusCode,
65+
Message: e.Message,
66+
Detail: detail,
67+
}
68+
}

routers/api/packages/container/manifest.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -57,7 +57,7 @@ func processManifest(ctx context.Context, mci *manifestCreationInfo, buf *packag
5757
}
5858

5959
if index.SchemaVersion != 2 {
60-
return "", errUnsupported.WithMessage("Schema version is not supported")
60+
return "", errUnsupported.WithDetail("Schema version is not supported")
6161
}
6262

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

0 commit comments

Comments
 (0)