...
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15 package ociserver
16
17 import (
18 "encoding/json"
19 "errors"
20 "fmt"
21 "net/http"
22
23 "cuelabs.dev/go/oci/ociregistry"
24 )
25
26 type wireError struct {
27 Code string `json:"code"`
28 Message string `json:"message,omitempty"`
29 Detail any `json:"detail,omitempty"`
30 }
31
32 type wireErrors struct {
33 Errors []wireError `json:"errors"`
34 }
35
36 func writeError(resp http.ResponseWriter, err error) {
37 e := wireError{
38 Message: err.Error(),
39 }
40 var ociErr ociregistry.Error
41 if errors.As(err, &ociErr) {
42 e.Code = ociErr.Code()
43 e.Detail = ociErr.Detail()
44 } else {
45
46
47 e.Code = "UNKNOWN"
48 }
49 httpStatus := http.StatusInternalServerError
50 var statusErr *httpStatusError
51 if errors.As(err, &statusErr) {
52 httpStatus = statusErr.status
53 } else if status, ok := errorStatuses[e.Code]; ok {
54 httpStatus = status
55 }
56 resp.Header().Set("Content-Type", "application/json")
57 resp.WriteHeader(httpStatus)
58
59 data, err := json.Marshal(wireErrors{
60 Errors: []wireError{e},
61 })
62 if err != nil {
63
64 }
65 resp.Write(data)
66 }
67
68 var errorStatuses = map[string]int{
69 ociregistry.ErrBlobUnknown.Code(): http.StatusNotFound,
70 ociregistry.ErrBlobUploadInvalid.Code(): http.StatusRequestedRangeNotSatisfiable,
71 ociregistry.ErrBlobUploadUnknown.Code(): http.StatusNotFound,
72 ociregistry.ErrDigestInvalid.Code(): http.StatusBadRequest,
73 ociregistry.ErrManifestBlobUnknown.Code(): http.StatusNotFound,
74 ociregistry.ErrManifestInvalid.Code(): http.StatusBadRequest,
75 ociregistry.ErrManifestUnknown.Code(): http.StatusNotFound,
76 ociregistry.ErrNameInvalid.Code(): http.StatusBadRequest,
77 ociregistry.ErrNameUnknown.Code(): http.StatusNotFound,
78 ociregistry.ErrSizeInvalid.Code(): http.StatusBadRequest,
79 ociregistry.ErrUnauthorized.Code(): http.StatusUnauthorized,
80 ociregistry.ErrDenied.Code(): http.StatusForbidden,
81 ociregistry.ErrUnsupported.Code(): http.StatusBadRequest,
82 ociregistry.ErrTooManyRequests.Code(): http.StatusTooManyRequests,
83 ociregistry.ErrRangeInvalid.Code(): http.StatusRequestedRangeNotSatisfiable,
84 }
85
86 func badAPIUseError(f string, a ...any) error {
87 return ociregistry.NewError(fmt.Sprintf(f, a...), ociregistry.ErrUnsupported.Code(), nil)
88 }
89
90 func withHTTPCode(status int, err error) error {
91 if err == nil {
92 panic("expected error to wrap")
93 }
94 return &httpStatusError{
95 err: err,
96 status: status,
97 }
98 }
99
100 type httpStatusError struct {
101 err error
102 status int
103 }
104
105 func (e *httpStatusError) Unwrap() error {
106 return e.err
107 }
108
109 func (e *httpStatusError) Error() string {
110 return e.err.Error()
111 }
112
View as plain text