github.com/cs3org/reva/v2@v2.27.7/pkg/errtypes/errtypes.go (about) 1 // Copyright 2018-2021 CERN 2 // 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 // In applying this license, CERN does not waive the privileges and immunities 16 // granted to it by virtue of its status as an Intergovernmental Organization 17 // or submit itself to any jurisdiction. 18 19 // Package errtypes contains definitions for common errors. 20 // It would have nice to call this package errors, err or error 21 // but errors clashes with github.com/pkg/errors, err is used for any error variable 22 // and error is a reserved word :) 23 package errtypes 24 25 import ( 26 "net/http" 27 "strings" 28 29 rpc "github.com/cs3org/go-cs3apis/cs3/rpc/v1beta1" 30 ) 31 32 // NotFound is the error to use when a something is not found. 33 type NotFound string 34 35 func (e NotFound) Error() string { return "error: not found: " + string(e) } 36 37 // IsNotFound implements the IsNotFound interface. 38 func (e NotFound) IsNotFound() {} 39 40 // InternalError is the error to use when we really don't know what happened. Use with care 41 type InternalError string 42 43 func (e InternalError) Error() string { return "internal error: " + string(e) } 44 45 // IsInternalError implements the IsInternalError interface. 46 func (e InternalError) IsInternalError() {} 47 48 // PermissionDenied is the error to use when a resource cannot be access because of missing permissions. 49 type PermissionDenied string 50 51 func (e PermissionDenied) Error() string { return "error: permission denied: " + string(e) } 52 53 // IsPermissionDenied implements the IsPermissionDenied interface. 54 func (e PermissionDenied) IsPermissionDenied() {} 55 56 // Locked is the error to use when a resource cannot be modified because of a lock. 57 type Locked string 58 59 func (e Locked) Error() string { return "error: locked by " + string(e) } 60 61 // LockID returns the lock ID that caused this error 62 func (e Locked) LockID() string { 63 return string(e) 64 } 65 66 // IsLocked implements the IsLocked interface. 67 func (e Locked) IsLocked() {} 68 69 // Aborted is the error to use when a client should retry at a higher level 70 // (e.g., when a client-specified test-and-set fails, indicating the 71 // client should restart a read-modify-write sequence) request fails 72 // because a requested etag or lock ID mismatches. 73 // 74 // HTTP Mapping: 412 Precondition Failed 75 type Aborted string 76 77 func (e Aborted) Error() string { return "error: aborted: " + string(e) } 78 79 // IsAborted implements the IsAborted interface. 80 func (e Aborted) IsAborted() {} 81 82 // PreconditionFailed is the error to use when a client should not retry until 83 // the system state has been explicitly fixed. E.g., if an "rmdir" 84 // fails because the directory is non-empty, PreconditionFailed 85 // should be returned since the client should not retry unless 86 // the files are deleted from the directory. PreconditionFailed should also be 87 // returned when an intermediate directory for an MKCOL or PUT is missing. 88 // 89 // # FIXME rename to FailedPrecondition to make it less confusable with the http status Precondition Failed 90 // 91 // HTTP Mapping: 400 Bad Request, 405 Method Not Allowed, 409 Conflict 92 type PreconditionFailed string 93 94 func (e PreconditionFailed) Error() string { return "error: precondition failed: " + string(e) } 95 96 // IsPreconditionFailed implements the IsPreconditionFailed interface. 97 func (e PreconditionFailed) IsPreconditionFailed() {} 98 99 // AlreadyExists is the error to use when a resource something is not found. 100 type AlreadyExists string 101 102 func (e AlreadyExists) Error() string { return "error: already exists: " + string(e) } 103 104 // IsAlreadyExists implements the IsAlreadyExists interface. 105 func (e AlreadyExists) IsAlreadyExists() {} 106 107 // UserRequired represents an error when a resource is not found. 108 type UserRequired string 109 110 func (e UserRequired) Error() string { return "error: user required: " + string(e) } 111 112 // IsUserRequired implements the IsUserRequired interface. 113 func (e UserRequired) IsUserRequired() {} 114 115 // InvalidCredentials is the error to use when receiving invalid credentials. 116 type InvalidCredentials string 117 118 func (e InvalidCredentials) Error() string { return "error: invalid credentials: " + string(e) } 119 120 // IsInvalidCredentials implements the IsInvalidCredentials interface. 121 func (e InvalidCredentials) IsInvalidCredentials() {} 122 123 // NotSupported is the error to use when an action is not supported. 124 type NotSupported string 125 126 func (e NotSupported) Error() string { return "error: not supported: " + string(e) } 127 128 // IsNotSupported implements the IsNotSupported interface. 129 func (e NotSupported) IsNotSupported() {} 130 131 // PartialContent is the error to use when the client request has partial data. 132 type PartialContent string 133 134 func (e PartialContent) Error() string { return "error: partial content: " + string(e) } 135 136 // IsPartialContent implements the IsPartialContent interface. 137 func (e PartialContent) IsPartialContent() {} 138 139 // BadRequest is the error to use when the server cannot or will not process the request (due to a client error). Reauthenticating won't help. 140 type BadRequest string 141 142 func (e BadRequest) Error() string { return "error: bad request: " + string(e) } 143 144 // IsBadRequest implements the IsBadRequest interface. 145 func (e BadRequest) IsBadRequest() {} 146 147 // ChecksumMismatch is the error to use when the transmitted hash does not match the calculated hash. 148 type ChecksumMismatch string 149 150 func (e ChecksumMismatch) Error() string { return "error: checksum mismatch: " + string(e) } 151 152 // IsChecksumMismatch implements the IsChecksumMismatch interface. 153 func (e ChecksumMismatch) IsChecksumMismatch() {} 154 155 // StatusChecksumMismatch 419 is an unofficial http status code in an unassigned range that is used for checksum mismatches 156 // Proposed by https://stackoverflow.com/a/35665694 157 // Official HTTP status code registry: https://www.iana.org/assignments/http-status-codes/http-status-codes.xhtml 158 // Note: TUS uses unassigned 460 Checksum-Mismatch 159 // RFC proposal for checksum digest uses a `Want-Digest` header: https://tools.ietf.org/html/rfc3230 160 // oc clienst issue: https://github.com/owncloud/core/issues/22711 161 const StatusChecksumMismatch = 419 162 163 // InsufficientStorage is the error to use when there is insufficient storage. 164 type InsufficientStorage string 165 166 func (e InsufficientStorage) Error() string { return "error: insufficient storage: " + string(e) } 167 168 // IsInsufficientStorage implements the IsInsufficientStorage interface. 169 func (e InsufficientStorage) IsInsufficientStorage() {} 170 171 // StatusCode returns StatusInsufficientStorage, this implementation is needed to allow TUS to cast the correct http errors. 172 func (e InsufficientStorage) StatusCode() int { 173 return StatusInsufficientStorage 174 } 175 176 // NotModified is the error to use when a resource was not modified, e.g. the requested etag did not change. 177 type NotModified string 178 179 func (e NotModified) Error() string { return "error: not modified: " + string(e) } 180 181 // IsNotModified implements the IsNotModified interface. 182 func (e NotModified) IsNotModified() {} 183 184 // StatusCode returns StatusInsufficientStorage, this implementation is needed to allow TUS to cast the correct http errors. 185 func (e NotModified) StatusCode() int { 186 return http.StatusNotModified 187 } 188 189 // Body returns the error body. This implementation is needed to allow TUS to cast the correct http errors 190 func (e InsufficientStorage) Body() []byte { 191 return []byte(e.Error()) 192 } 193 194 // StatusInsufficientStorage 507 is an official HTTP status code to indicate that there is insufficient storage 195 // https://developer.mozilla.org/en-US/docs/Web/HTTP/Status/507 196 const StatusInsufficientStorage = 507 197 198 // TooEarly is the error to use when some are not finished job over resource is still in process. 199 type TooEarly string 200 201 func (e TooEarly) Error() string { return "error: too early: " + string(e) } 202 203 // IsTooEarly implements the IsTooEarly interface. 204 func (e TooEarly) IsTooEarly() {} 205 206 // IsNotFound is the interface to implement 207 // to specify that a resource is not found. 208 type IsNotFound interface { 209 IsNotFound() 210 } 211 212 // IsAlreadyExists is the interface to implement 213 // to specify that a resource already exists. 214 type IsAlreadyExists interface { 215 IsAlreadyExists() 216 } 217 218 // IsInternalError is the interface to implement 219 // to specify that there was some internal error 220 type IsInternalError interface { 221 IsInternalError() 222 } 223 224 // IsUserRequired is the interface to implement 225 // to specify that a user is required. 226 type IsUserRequired interface { 227 IsUserRequired() 228 } 229 230 // IsInvalidCredentials is the interface to implement 231 // to specify that credentials were wrong. 232 type IsInvalidCredentials interface { 233 IsInvalidCredentials() 234 } 235 236 // IsNotSupported is the interface to implement 237 // to specify that an action is not supported. 238 type IsNotSupported interface { 239 IsNotSupported() 240 } 241 242 // IsPermissionDenied is the interface to implement 243 // to specify that an action is denied. 244 type IsPermissionDenied interface { 245 IsPermissionDenied() 246 } 247 248 // IsLocked is the interface to implement 249 // to specify that a resource is locked. 250 type IsLocked interface { 251 IsLocked() 252 } 253 254 // IsAborted is the interface to implement 255 // to specify that a request was aborted. 256 type IsAborted interface { 257 IsAborted() 258 } 259 260 // IsPreconditionFailed is the interface to implement 261 // to specify that a precondition failed. 262 type IsPreconditionFailed interface { 263 IsPreconditionFailed() 264 } 265 266 // IsPartialContent is the interface to implement 267 // to specify that the client request has partial data. 268 type IsPartialContent interface { 269 IsPartialContent() 270 } 271 272 // IsBadRequest is the interface to implement 273 // to specify that the server cannot or will not process the request. 274 type IsBadRequest interface { 275 IsBadRequest() 276 } 277 278 // IsChecksumMismatch is the interface to implement 279 // to specify that a checksum does not match. 280 type IsChecksumMismatch interface { 281 IsChecksumMismatch() 282 } 283 284 // IsInsufficientStorage is the interface to implement 285 // to specify that there is insufficient storage. 286 type IsInsufficientStorage interface { 287 IsInsufficientStorage() 288 } 289 290 // IsTooEarly is the interface to implement 291 // to specify that there is some not finished job over resource is still in process. 292 type IsTooEarly interface { 293 IsTooEarly() 294 } 295 296 // NewErrtypeFromStatus maps a rpc status to an errtype 297 func NewErrtypeFromStatus(status *rpc.Status) error { 298 switch status.Code { 299 case rpc.Code_CODE_OK: 300 return nil 301 case rpc.Code_CODE_NOT_FOUND: 302 return NotFound(status.Message) 303 case rpc.Code_CODE_ALREADY_EXISTS: 304 return AlreadyExists(status.Message) 305 // case rpc.Code_CODE_FAILED_PRECONDITION: ? 306 // return UserRequired(status.Message) 307 // case rpc.Code_CODE_PERMISSION_DENIED: ? 308 // IsInvalidCredentials 309 case rpc.Code_CODE_UNIMPLEMENTED: 310 return NotSupported(status.Message) 311 case rpc.Code_CODE_PERMISSION_DENIED: 312 return PermissionDenied(status.Message) 313 case rpc.Code_CODE_LOCKED: 314 // FIXME make something better for that 315 msg := strings.Split(status.Message, "error: locked by ") 316 if len(msg) > 1 { 317 return Locked(msg[len(msg)-1]) 318 } 319 return Locked(status.Message) 320 // case rpc.Code_CODE_DATA_LOSS: ? 321 // IsPartialContent 322 case rpc.Code_CODE_ABORTED: 323 return Aborted(status.Message) 324 case rpc.Code_CODE_FAILED_PRECONDITION: 325 return PreconditionFailed(status.Message) 326 case rpc.Code_CODE_INSUFFICIENT_STORAGE: 327 return InsufficientStorage(status.Message) 328 case rpc.Code_CODE_INVALID_ARGUMENT, rpc.Code_CODE_OUT_OF_RANGE: 329 return BadRequest(status.Message) 330 case rpc.Code_CODE_TOO_EARLY: 331 return TooEarly(status.Message) 332 default: 333 return InternalError(status.Message) 334 } 335 } 336 337 // NewErrtypeFromHTTPStatusCode maps a http status to an errtype 338 func NewErrtypeFromHTTPStatusCode(code int, message string) error { 339 switch code { 340 case http.StatusOK: 341 return nil 342 case http.StatusNotFound: 343 return NotFound(message) 344 case http.StatusConflict: 345 return AlreadyExists(message) 346 case http.StatusNotImplemented: 347 return NotSupported(message) 348 case http.StatusNotModified: 349 return NotModified(message) 350 case http.StatusForbidden: 351 return PermissionDenied(message) 352 case http.StatusLocked: 353 return Locked(message) 354 case http.StatusPreconditionFailed: 355 return Aborted(message) 356 case http.StatusMethodNotAllowed: 357 return PreconditionFailed(message) 358 case http.StatusInsufficientStorage: 359 return InsufficientStorage(message) 360 case http.StatusBadRequest: 361 return BadRequest(message) 362 case http.StatusPartialContent: 363 return PartialContent(message) 364 case http.StatusTooEarly: 365 return TooEarly(message) 366 case StatusChecksumMismatch: 367 return ChecksumMismatch(message) 368 default: 369 return InternalError(message) 370 } 371 } 372 373 // NewHTTPStatusCodeFromErrtype maps an errtype to a http status 374 func NewHTTPStatusCodeFromErrtype(err error) int { 375 switch err.(type) { 376 case NotFound: 377 return http.StatusNotFound 378 case AlreadyExists: 379 return http.StatusConflict 380 case NotSupported: 381 return http.StatusNotImplemented 382 case NotModified: 383 return http.StatusNotModified 384 case InvalidCredentials: 385 return http.StatusUnauthorized 386 case PermissionDenied: 387 return http.StatusForbidden 388 case Locked: 389 return http.StatusLocked 390 case Aborted: 391 return http.StatusPreconditionFailed 392 case PreconditionFailed: 393 return http.StatusMethodNotAllowed 394 case InsufficientStorage: 395 return http.StatusInsufficientStorage 396 case BadRequest: 397 return http.StatusBadRequest 398 case PartialContent: 399 return http.StatusPartialContent 400 case TooEarly: 401 return http.StatusTooEarly 402 case ChecksumMismatch: 403 return StatusChecksumMismatch 404 default: 405 return http.StatusInternalServerError 406 } 407 }