diff options
| author | Rutger Broekhoff | 2023-12-29 21:31:53 +0100 |
|---|---|---|
| committer | Rutger Broekhoff | 2023-12-29 21:31:53 +0100 |
| commit | 404aeae4545d2426c089a5f8d5e82dae56f5212b (patch) | |
| tree | 2d84e00af272b39fc04f3795ae06bc48970e57b5 /vendor/github.com/minio/minio-go/v7/api-error-response.go | |
| parent | 209d8b0187ed025dec9ac149ebcced3462877bff (diff) | |
| download | gitolfs3-404aeae4545d2426c089a5f8d5e82dae56f5212b.tar.gz gitolfs3-404aeae4545d2426c089a5f8d5e82dae56f5212b.zip | |
Make Nix builds work
Diffstat (limited to 'vendor/github.com/minio/minio-go/v7/api-error-response.go')
| -rw-r--r-- | vendor/github.com/minio/minio-go/v7/api-error-response.go | 284 |
1 files changed, 284 insertions, 0 deletions
diff --git a/vendor/github.com/minio/minio-go/v7/api-error-response.go b/vendor/github.com/minio/minio-go/v7/api-error-response.go new file mode 100644 index 0000000..7df211f --- /dev/null +++ b/vendor/github.com/minio/minio-go/v7/api-error-response.go | |||
| @@ -0,0 +1,284 @@ | |||
| 1 | /* | ||
| 2 | * MinIO Go Library for Amazon S3 Compatible Cloud Storage | ||
| 3 | * Copyright 2015-2020 MinIO, Inc. | ||
| 4 | * | ||
| 5 | * Licensed under the Apache License, Version 2.0 (the "License"); | ||
| 6 | * you may not use this file except in compliance with the License. | ||
| 7 | * You may obtain a copy of the License at | ||
| 8 | * | ||
| 9 | * http://www.apache.org/licenses/LICENSE-2.0 | ||
| 10 | * | ||
| 11 | * Unless required by applicable law or agreed to in writing, software | ||
| 12 | * distributed under the License is distributed on an "AS IS" BASIS, | ||
| 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
| 14 | * See the License for the specific language governing permissions and | ||
| 15 | * limitations under the License. | ||
| 16 | */ | ||
| 17 | |||
| 18 | package minio | ||
| 19 | |||
| 20 | import ( | ||
| 21 | "bytes" | ||
| 22 | "encoding/xml" | ||
| 23 | "fmt" | ||
| 24 | "io" | ||
| 25 | "net/http" | ||
| 26 | "strings" | ||
| 27 | ) | ||
| 28 | |||
| 29 | /* **** SAMPLE ERROR RESPONSE **** | ||
| 30 | <?xml version="1.0" encoding="UTF-8"?> | ||
| 31 | <Error> | ||
| 32 | <Code>AccessDenied</Code> | ||
| 33 | <Message>Access Denied</Message> | ||
| 34 | <BucketName>bucketName</BucketName> | ||
| 35 | <Key>objectName</Key> | ||
| 36 | <RequestId>F19772218238A85A</RequestId> | ||
| 37 | <HostId>GuWkjyviSiGHizehqpmsD1ndz5NClSP19DOT+s2mv7gXGQ8/X1lhbDGiIJEXpGFD</HostId> | ||
| 38 | </Error> | ||
| 39 | */ | ||
| 40 | |||
| 41 | // ErrorResponse - Is the typed error returned by all API operations. | ||
| 42 | // ErrorResponse struct should be comparable since it is compared inside | ||
| 43 | // golang http API (https://github.com/golang/go/issues/29768) | ||
| 44 | type ErrorResponse struct { | ||
| 45 | XMLName xml.Name `xml:"Error" json:"-"` | ||
| 46 | Code string | ||
| 47 | Message string | ||
| 48 | BucketName string | ||
| 49 | Key string | ||
| 50 | Resource string | ||
| 51 | RequestID string `xml:"RequestId"` | ||
| 52 | HostID string `xml:"HostId"` | ||
| 53 | |||
| 54 | // Region where the bucket is located. This header is returned | ||
| 55 | // only in HEAD bucket and ListObjects response. | ||
| 56 | Region string | ||
| 57 | |||
| 58 | // Captures the server string returned in response header. | ||
| 59 | Server string | ||
| 60 | |||
| 61 | // Underlying HTTP status code for the returned error | ||
| 62 | StatusCode int `xml:"-" json:"-"` | ||
| 63 | } | ||
| 64 | |||
| 65 | // ToErrorResponse - Returns parsed ErrorResponse struct from body and | ||
| 66 | // http headers. | ||
| 67 | // | ||
| 68 | // For example: | ||
| 69 | // | ||
| 70 | // import s3 "github.com/minio/minio-go/v7" | ||
| 71 | // ... | ||
| 72 | // ... | ||
| 73 | // reader, stat, err := s3.GetObject(...) | ||
| 74 | // if err != nil { | ||
| 75 | // resp := s3.ToErrorResponse(err) | ||
| 76 | // } | ||
| 77 | // ... | ||
| 78 | func ToErrorResponse(err error) ErrorResponse { | ||
| 79 | switch err := err.(type) { | ||
| 80 | case ErrorResponse: | ||
| 81 | return err | ||
| 82 | default: | ||
| 83 | return ErrorResponse{} | ||
| 84 | } | ||
| 85 | } | ||
| 86 | |||
| 87 | // Error - Returns S3 error string. | ||
| 88 | func (e ErrorResponse) Error() string { | ||
| 89 | if e.Message == "" { | ||
| 90 | msg, ok := s3ErrorResponseMap[e.Code] | ||
| 91 | if !ok { | ||
| 92 | msg = fmt.Sprintf("Error response code %s.", e.Code) | ||
| 93 | } | ||
| 94 | return msg | ||
| 95 | } | ||
| 96 | return e.Message | ||
| 97 | } | ||
| 98 | |||
| 99 | // Common string for errors to report issue location in unexpected | ||
| 100 | // cases. | ||
| 101 | const ( | ||
| 102 | reportIssue = "Please report this issue at https://github.com/minio/minio-go/issues." | ||
| 103 | ) | ||
| 104 | |||
| 105 | // xmlDecodeAndBody reads the whole body up to 1MB and | ||
| 106 | // tries to XML decode it into v. | ||
| 107 | // The body that was read and any error from reading or decoding is returned. | ||
| 108 | func xmlDecodeAndBody(bodyReader io.Reader, v interface{}) ([]byte, error) { | ||
| 109 | // read the whole body (up to 1MB) | ||
| 110 | const maxBodyLength = 1 << 20 | ||
| 111 | body, err := io.ReadAll(io.LimitReader(bodyReader, maxBodyLength)) | ||
| 112 | if err != nil { | ||
| 113 | return nil, err | ||
| 114 | } | ||
| 115 | return bytes.TrimSpace(body), xmlDecoder(bytes.NewReader(body), v) | ||
| 116 | } | ||
| 117 | |||
| 118 | // httpRespToErrorResponse returns a new encoded ErrorResponse | ||
| 119 | // structure as error. | ||
| 120 | func httpRespToErrorResponse(resp *http.Response, bucketName, objectName string) error { | ||
| 121 | if resp == nil { | ||
| 122 | msg := "Empty http response. " + reportIssue | ||
| 123 | return errInvalidArgument(msg) | ||
| 124 | } | ||
| 125 | |||
| 126 | errResp := ErrorResponse{ | ||
| 127 | StatusCode: resp.StatusCode, | ||
| 128 | Server: resp.Header.Get("Server"), | ||
| 129 | } | ||
| 130 | |||
| 131 | errBody, err := xmlDecodeAndBody(resp.Body, &errResp) | ||
| 132 | // Xml decoding failed with no body, fall back to HTTP headers. | ||
| 133 | if err != nil { | ||
| 134 | switch resp.StatusCode { | ||
| 135 | case http.StatusNotFound: | ||
| 136 | if objectName == "" { | ||
| 137 | errResp = ErrorResponse{ | ||
| 138 | StatusCode: resp.StatusCode, | ||
| 139 | Code: "NoSuchBucket", | ||
| 140 | Message: "The specified bucket does not exist.", | ||
| 141 | BucketName: bucketName, | ||
| 142 | } | ||
| 143 | } else { | ||
| 144 | errResp = ErrorResponse{ | ||
| 145 | StatusCode: resp.StatusCode, | ||
| 146 | Code: "NoSuchKey", | ||
| 147 | Message: "The specified key does not exist.", | ||
| 148 | BucketName: bucketName, | ||
| 149 | Key: objectName, | ||
| 150 | } | ||
| 151 | } | ||
| 152 | case http.StatusForbidden: | ||
| 153 | errResp = ErrorResponse{ | ||
| 154 | StatusCode: resp.StatusCode, | ||
| 155 | Code: "AccessDenied", | ||
| 156 | Message: "Access Denied.", | ||
| 157 | BucketName: bucketName, | ||
| 158 | Key: objectName, | ||
| 159 | } | ||
| 160 | case http.StatusConflict: | ||
| 161 | errResp = ErrorResponse{ | ||
| 162 | StatusCode: resp.StatusCode, | ||
| 163 | Code: "Conflict", | ||
| 164 | Message: "Bucket not empty.", | ||
| 165 | BucketName: bucketName, | ||
| 166 | } | ||
| 167 | case http.StatusPreconditionFailed: | ||
| 168 | errResp = ErrorResponse{ | ||
| 169 | StatusCode: resp.StatusCode, | ||
| 170 | Code: "PreconditionFailed", | ||
| 171 | Message: s3ErrorResponseMap["PreconditionFailed"], | ||
| 172 | BucketName: bucketName, | ||
| 173 | Key: objectName, | ||
| 174 | } | ||
| 175 | default: | ||
| 176 | msg := resp.Status | ||
| 177 | if len(errBody) > 0 { | ||
| 178 | msg = string(errBody) | ||
| 179 | if len(msg) > 1024 { | ||
| 180 | msg = msg[:1024] + "..." | ||
| 181 | } | ||
| 182 | } | ||
| 183 | errResp = ErrorResponse{ | ||
| 184 | StatusCode: resp.StatusCode, | ||
| 185 | Code: resp.Status, | ||
| 186 | Message: msg, | ||
| 187 | BucketName: bucketName, | ||
| 188 | } | ||
| 189 | } | ||
| 190 | } | ||
| 191 | |||
| 192 | code := resp.Header.Get("x-minio-error-code") | ||
| 193 | if code != "" { | ||
| 194 | errResp.Code = code | ||
| 195 | } | ||
| 196 | desc := resp.Header.Get("x-minio-error-desc") | ||
| 197 | if desc != "" { | ||
| 198 | errResp.Message = strings.Trim(desc, `"`) | ||
| 199 | } | ||
| 200 | |||
| 201 | // Save hostID, requestID and region information | ||
| 202 | // from headers if not available through error XML. | ||
| 203 | if errResp.RequestID == "" { | ||
| 204 | errResp.RequestID = resp.Header.Get("x-amz-request-id") | ||
| 205 | } | ||
| 206 | if errResp.HostID == "" { | ||
| 207 | errResp.HostID = resp.Header.Get("x-amz-id-2") | ||
| 208 | } | ||
| 209 | if errResp.Region == "" { | ||
| 210 | errResp.Region = resp.Header.Get("x-amz-bucket-region") | ||
| 211 | } | ||
| 212 | if errResp.Code == "InvalidRegion" && errResp.Region != "" { | ||
| 213 | errResp.Message = fmt.Sprintf("Region does not match, expecting region ‘%s’.", errResp.Region) | ||
| 214 | } | ||
| 215 | |||
| 216 | return errResp | ||
| 217 | } | ||
| 218 | |||
| 219 | // errTransferAccelerationBucket - bucket name is invalid to be used with transfer acceleration. | ||
| 220 | func errTransferAccelerationBucket(bucketName string) error { | ||
| 221 | return ErrorResponse{ | ||
| 222 | StatusCode: http.StatusBadRequest, | ||
| 223 | Code: "InvalidArgument", | ||
| 224 | Message: "The name of the bucket used for Transfer Acceleration must be DNS-compliant and must not contain periods ‘.’.", | ||
| 225 | BucketName: bucketName, | ||
| 226 | } | ||
| 227 | } | ||
| 228 | |||
| 229 | // errEntityTooLarge - Input size is larger than supported maximum. | ||
| 230 | func errEntityTooLarge(totalSize, maxObjectSize int64, bucketName, objectName string) error { | ||
| 231 | msg := fmt.Sprintf("Your proposed upload size ‘%d’ exceeds the maximum allowed object size ‘%d’ for single PUT operation.", totalSize, maxObjectSize) | ||
| 232 | return ErrorResponse{ | ||
| 233 | StatusCode: http.StatusBadRequest, | ||
| 234 | Code: "EntityTooLarge", | ||
| 235 | Message: msg, | ||
| 236 | BucketName: bucketName, | ||
| 237 | Key: objectName, | ||
| 238 | } | ||
| 239 | } | ||
| 240 | |||
| 241 | // errEntityTooSmall - Input size is smaller than supported minimum. | ||
| 242 | func errEntityTooSmall(totalSize int64, bucketName, objectName string) error { | ||
| 243 | msg := fmt.Sprintf("Your proposed upload size ‘%d’ is below the minimum allowed object size ‘0B’ for single PUT operation.", totalSize) | ||
| 244 | return ErrorResponse{ | ||
| 245 | StatusCode: http.StatusBadRequest, | ||
| 246 | Code: "EntityTooSmall", | ||
| 247 | Message: msg, | ||
| 248 | BucketName: bucketName, | ||
| 249 | Key: objectName, | ||
| 250 | } | ||
| 251 | } | ||
| 252 | |||
| 253 | // errUnexpectedEOF - Unexpected end of file reached. | ||
| 254 | func errUnexpectedEOF(totalRead, totalSize int64, bucketName, objectName string) error { | ||
| 255 | msg := fmt.Sprintf("Data read ‘%d’ is not equal to the size ‘%d’ of the input Reader.", totalRead, totalSize) | ||
| 256 | return ErrorResponse{ | ||
| 257 | StatusCode: http.StatusBadRequest, | ||
| 258 | Code: "UnexpectedEOF", | ||
| 259 | Message: msg, | ||
| 260 | BucketName: bucketName, | ||
| 261 | Key: objectName, | ||
| 262 | } | ||
| 263 | } | ||
| 264 | |||
| 265 | // errInvalidArgument - Invalid argument response. | ||
| 266 | func errInvalidArgument(message string) error { | ||
| 267 | return ErrorResponse{ | ||
| 268 | StatusCode: http.StatusBadRequest, | ||
| 269 | Code: "InvalidArgument", | ||
| 270 | Message: message, | ||
| 271 | RequestID: "minio", | ||
| 272 | } | ||
| 273 | } | ||
| 274 | |||
| 275 | // errAPINotSupported - API not supported response | ||
| 276 | // The specified API call is not supported | ||
| 277 | func errAPINotSupported(message string) error { | ||
| 278 | return ErrorResponse{ | ||
| 279 | StatusCode: http.StatusNotImplemented, | ||
| 280 | Code: "APINotSupported", | ||
| 281 | Message: message, | ||
| 282 | RequestID: "minio", | ||
| 283 | } | ||
| 284 | } | ||