github.com/opcr-io/oras-go/v2@v2.0.0-20231122155130-eb4260d8a0ae/registry/remote/errcode/errors.go (about) 1 /* 2 Copyright The ORAS Authors. 3 Licensed under the Apache License, Version 2.0 (the "License"); 4 you may not use this file except in compliance with the License. 5 You may obtain a copy of the License at 6 7 http://www.apache.org/licenses/LICENSE-2.0 8 9 Unless required by applicable law or agreed to in writing, software 10 distributed under the License is distributed on an "AS IS" BASIS, 11 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 See the License for the specific language governing permissions and 13 limitations under the License. 14 */ 15 16 package errcode 17 18 import ( 19 "fmt" 20 "net/http" 21 "net/url" 22 "strings" 23 "unicode" 24 ) 25 26 // References: 27 // - https://github.com/opencontainers/distribution-spec/blob/v1.1.0-rc1/spec.md#error-codes 28 // - https://docs.docker.com/registry/spec/api/#errors-2 29 const ( 30 ErrorCodeBlobUnknown = "BLOB_UNKNOWN" 31 ErrorCodeBlobUploadInvalid = "BLOB_UPLOAD_INVALID" 32 ErrorCodeBlobUploadUnknown = "BLOB_UPLOAD_UNKNOWN" 33 ErrorCodeDigestInvalid = "DIGEST_INVALID" 34 ErrorCodeManifestBlobUnknown = "MANIFEST_BLOB_UNKNOWN" 35 ErrorCodeManifestInvalid = "MANIFEST_INVALID" 36 ErrorCodeManifestUnknown = "MANIFEST_UNKNOWN" 37 ErrorCodeNameInvalid = "NAME_INVALID" 38 ErrorCodeNameUnknown = "NAME_UNKNOWN" 39 ErrorCodeSizeInvalid = "SIZE_INVALID" 40 ErrorCodeUnauthorized = "UNAUTHORIZED" 41 ErrorCodeDenied = "DENIED" 42 ErrorCodeUnsupported = "UNSUPPORTED" 43 ) 44 45 // Error represents a response inner error returned by the remote 46 // registry. 47 // References: 48 // - https://github.com/opencontainers/distribution-spec/blob/v1.1.0-rc1/spec.md#error-codes 49 // - https://docs.docker.com/registry/spec/api/#errors-2 50 type Error struct { 51 Code string `json:"code"` 52 Message string `json:"message"` 53 Detail any `json:"detail,omitempty"` 54 } 55 56 // Error returns a error string describing the error. 57 func (e Error) Error() string { 58 code := strings.Map(func(r rune) rune { 59 if r == '_' { 60 return ' ' 61 } 62 return unicode.ToLower(r) 63 }, e.Code) 64 if e.Message == "" { 65 return code 66 } 67 if e.Detail == nil { 68 return fmt.Sprintf("%s: %s", code, e.Message) 69 } 70 return fmt.Sprintf("%s: %s: %v", code, e.Message, e.Detail) 71 } 72 73 // Errors represents a list of response inner errors returned by the remote 74 // server. 75 // References: 76 // - https://github.com/opencontainers/distribution-spec/blob/v1.1.0-rc1/spec.md#error-codes 77 // - https://docs.docker.com/registry/spec/api/#errors-2 78 type Errors []Error 79 80 // Error returns a error string describing the error. 81 func (errs Errors) Error() string { 82 switch len(errs) { 83 case 0: 84 return "<nil>" 85 case 1: 86 return errs[0].Error() 87 } 88 var errmsgs []string 89 for _, err := range errs { 90 errmsgs = append(errmsgs, err.Error()) 91 } 92 return strings.Join(errmsgs, "; ") 93 } 94 95 // Unwrap returns the inner error only when there is exactly one error. 96 func (errs Errors) Unwrap() error { 97 if len(errs) == 1 { 98 return errs[0] 99 } 100 return nil 101 } 102 103 // ErrorResponse represents an error response. 104 type ErrorResponse struct { 105 Method string 106 URL *url.URL 107 StatusCode int 108 Errors Errors 109 } 110 111 // Error returns a error string describing the error. 112 func (err *ErrorResponse) Error() string { 113 var errmsg string 114 if len(err.Errors) > 0 { 115 errmsg = err.Errors.Error() 116 } else { 117 errmsg = http.StatusText(err.StatusCode) 118 } 119 return fmt.Sprintf("%s %q: response status code %d: %s", err.Method, err.URL, err.StatusCode, errmsg) 120 } 121 122 // Unwrap returns the internal errors of err if any. 123 func (err *ErrorResponse) Unwrap() error { 124 if len(err.Errors) == 0 { 125 return nil 126 } 127 return err.Errors 128 }