github.com/keybase/client/go@v0.0.0-20240309051027-028f7c731f8b/kbfs/kbfsblock/server_errors.go (about) 1 // Copyright 2016 Keybase Inc. All rights reserved. 2 // Use of this source code is governed by a BSD 3 // license that can be found in the LICENSE file. 4 5 package kbfsblock 6 7 import ( 8 "errors" 9 "fmt" 10 "strconv" 11 12 "github.com/keybase/client/go/libkb" 13 "github.com/keybase/client/go/protocol/keybase1" 14 "github.com/keybase/go-framed-msgpack-rpc/rpc" 15 ) 16 17 const ( 18 // StatusCodeServerError is the error code for a generic block server error. 19 StatusCodeServerError = 2700 20 // StatusCodeServerErrorBadRequest is the error code for a generic client error. 21 StatusCodeServerErrorBadRequest = 2701 22 // StatusCodeServerErrorUnauthorized is the error code for when the session has not been validated 23 StatusCodeServerErrorUnauthorized = 2702 24 // StatusCodeServerErrorOverQuota is the error code for when the user has exceeded his quota 25 StatusCodeServerErrorOverQuota = 2703 26 // StatusCodeServerErrorBlockNonExistent is the error code for when bserver cannot find a block 27 StatusCodeServerErrorBlockNonExistent = 2704 28 // StatusCodeServerErrorBlockArchived is the error code for a block has been archived 29 StatusCodeServerErrorBlockArchived = 2705 30 // StatusCodeServerErrorNoPermission is the error code for when there's no permission 31 StatusCodeServerErrorNoPermission = 2706 32 // StatusCodeServerErrorBlockDeleted is the error code for a block has been deleted 33 StatusCodeServerErrorBlockDeleted = 2707 34 // StatusCodeServerErrorNonceNonExistent is the error code when a nonce cannot be found 35 StatusCodeServerErrorNonceNonExistent = 2708 36 // StatusCodeServerErrorMaxRefExceeded is the error code to indicate there are too many refs to a block 37 StatusCodeServerErrorMaxRefExceeded = 2709 38 // StatusCodeServerErrorThrottle is the error code to indicate the client should initiate backoff. 39 StatusCodeServerErrorThrottle = 2799 40 ) 41 42 // ServerError is a generic bserver-side error. 43 type ServerError struct { 44 Msg string 45 } 46 47 // ToStatus implements the ExportableError interface for ServerError. 48 func (e ServerError) ToStatus() (s keybase1.Status) { 49 s.Code = StatusCodeServerError 50 s.Name = "SERVER_ERROR" 51 s.Desc = e.Msg 52 return 53 } 54 55 // Error implements the Error interface for ServerError. 56 func (e ServerError) Error() string { 57 return "ServerError{" + e.Msg + "}" 58 } 59 60 // ServerErrorBadRequest is a generic client-side error. 61 type ServerErrorBadRequest struct { 62 Msg string 63 } 64 65 // ToStatus implements the ExportableError interface for ServerError. 66 func (e ServerErrorBadRequest) ToStatus() (s keybase1.Status) { 67 s.Code = StatusCodeServerErrorBadRequest 68 s.Name = "BAD_REQUEST" 69 s.Desc = e.Msg 70 return 71 } 72 73 // Error implements the Error interface for ServerError. 74 func (e ServerErrorBadRequest) Error() string { 75 if e.Msg == "" { 76 return "Server: bad client request" 77 } 78 return "ServerErrorBadRequest{" + e.Msg + "}" 79 } 80 81 // ServerErrorUnauthorized is a generic client-side error. 82 type ServerErrorUnauthorized struct { 83 Msg string 84 } 85 86 // ToStatus implements the ExportableError interface for ServerErrorUnauthorized. 87 func (e ServerErrorUnauthorized) ToStatus() (s keybase1.Status) { 88 s.Code = StatusCodeServerErrorUnauthorized 89 s.Name = "SESSION_UNAUTHORIZED" 90 s.Desc = e.Msg 91 return 92 } 93 94 // Error implements the Error interface for ServerErrorUnauthorized. 95 func (e ServerErrorUnauthorized) Error() string { 96 if e.Msg == "" { 97 return "Server: session not validated" 98 } 99 return "ServerErrorUnauthorized{" + e.Msg + "}" 100 } 101 102 // ServerErrorOverQuota is returned when a user is over quota. 103 type ServerErrorOverQuota struct { 104 Msg string 105 // Usage indicates the current usage 106 Usage int64 107 // Limit indicates the current quota limit 108 Limit int64 109 // Throttled indicates if request has not been completed due to server throttle 110 Throttled bool 111 } 112 113 // ToStatus implements the ExportableError interface for ServerErrorOverQuota. 114 func (e ServerErrorOverQuota) ToStatus() (s keybase1.Status) { 115 s.Code = StatusCodeServerErrorOverQuota 116 s.Name = "QUOTA_EXCEEDED" 117 s.Desc = e.Msg 118 s.Fields = append(s.Fields, keybase1.StringKVPair{ 119 Key: "QUOTA_USAGE", 120 Value: strconv.FormatInt(e.Usage, 10), 121 }) 122 s.Fields = append(s.Fields, keybase1.StringKVPair{ 123 Key: "QUOTA_LIMIT", 124 Value: strconv.FormatInt(e.Limit, 10), 125 }) 126 s.Fields = append(s.Fields, keybase1.StringKVPair{ 127 Key: "QUOTA_THROTTLE", 128 Value: strconv.FormatBool(e.Throttled), 129 }) 130 return 131 } 132 133 // Error implements the Error interface for ServerErrorOverQuota. 134 func (e ServerErrorOverQuota) Error() string { 135 return fmt.Sprintf( 136 "ServerErrorOverQuota{Msg: %q, Usage: %d, Limit: %d, Throttled: %t}", 137 e.Msg, e.Usage, e.Limit, e.Throttled) 138 } 139 140 // ServerErrorBlockNonExistent is an exportable error from bserver 141 type ServerErrorBlockNonExistent struct { 142 Msg string 143 } 144 145 // ToStatus implements the ExportableError interface for ServerErrorBlockNonExistent 146 func (e ServerErrorBlockNonExistent) ToStatus() (s keybase1.Status) { 147 s.Code = StatusCodeServerErrorBlockNonExistent 148 s.Name = "BLOCK_NONEXISTENT" 149 s.Desc = e.Msg 150 return 151 } 152 153 // Error implements the Error interface for ServerErrorBlockNonExistent. 154 func (e ServerErrorBlockNonExistent) Error() string { 155 if e.Msg == "" { 156 return "Server: block does not exist" 157 } 158 return "ServerErrorBlockNonExistent{" + e.Msg + "}" 159 } 160 161 // ServerErrorBlockArchived is an exportable error from bserver 162 type ServerErrorBlockArchived struct { 163 Msg string 164 } 165 166 // ToStatus implements the ExportableError interface for ServerErrorBlockArchived 167 func (e ServerErrorBlockArchived) ToStatus() (s keybase1.Status) { 168 s.Code = StatusCodeServerErrorBlockArchived 169 s.Name = "BLOCK_ARCHIVED" 170 s.Desc = e.Msg 171 return 172 } 173 174 // Error implements the Error interface for ServerErrorBlockArchived. 175 func (e ServerErrorBlockArchived) Error() string { 176 if e.Msg == "" { 177 return "Server: block is archived" 178 } 179 return "ServerErrorBlockArchived{" + e.Msg + "}" 180 } 181 182 // ServerErrorBlockDeleted is an exportable error from bserver 183 type ServerErrorBlockDeleted struct { 184 Msg string 185 } 186 187 // ToStatus implements the ExportableError interface for ServerErrorBlockDeleted 188 func (e ServerErrorBlockDeleted) ToStatus() (s keybase1.Status) { 189 s.Code = StatusCodeServerErrorBlockDeleted 190 s.Name = "BLOCK_DELETED" 191 s.Desc = e.Msg 192 return 193 } 194 195 // Error implements the Error interface for ServerErrorBlockDeleted 196 func (e ServerErrorBlockDeleted) Error() string { 197 if e.Msg == "" { 198 return "Server: block is deleted" 199 } 200 return "ServerErrorBlockDeleted{" + e.Msg + "}" 201 } 202 203 // ServerErrorNoPermission is an exportable error from bserver 204 type ServerErrorNoPermission struct { 205 Msg string 206 } 207 208 // ToStatus implements the ExportableError interface for ServerErrorBlockArchived 209 func (e ServerErrorNoPermission) ToStatus() (s keybase1.Status) { 210 s.Code = StatusCodeServerErrorNoPermission 211 s.Name = "NO_PERMISSION" 212 s.Desc = e.Msg 213 return 214 } 215 216 // Error implements the Error interface for ServerErrorNoPermission. 217 func (e ServerErrorNoPermission) Error() string { 218 if e.Msg == "" { 219 return "Server: permission denied" 220 } 221 return "ServerErrorNoPermission{" + e.Msg + "}" 222 } 223 224 // ServerErrorNonceNonExistent is an exportable error from bserver 225 type ServerErrorNonceNonExistent struct { 226 Msg string 227 } 228 229 // ToStatus implements the ExportableError interface for ServerErrorNonceNonExistent 230 func (e ServerErrorNonceNonExistent) ToStatus() (s keybase1.Status) { 231 s.Code = StatusCodeServerErrorNonceNonExistent 232 s.Name = "BLOCK_NONCENONEXISTENT" 233 s.Desc = e.Msg 234 return 235 } 236 237 // Error implements the Error interface for ServerErrornonceNonExistent. 238 func (e ServerErrorNonceNonExistent) Error() string { 239 if e.Msg == "" { 240 return "Server: reference nonce does not exist" 241 } 242 return "ServerErrorNonceNonExistent{" + e.Msg + "}" 243 } 244 245 // ServerErrorMaxRefExceeded is an exportable error from bserver 246 type ServerErrorMaxRefExceeded struct { 247 Msg string 248 } 249 250 // ToStatus implements the ExportableError interface for ServerErrorMaxRefExceeded 251 func (e ServerErrorMaxRefExceeded) ToStatus() (s keybase1.Status) { 252 s.Code = StatusCodeServerErrorMaxRefExceeded 253 s.Name = "BLOCK_MAXREFEXCEEDED" 254 s.Desc = e.Msg 255 return 256 } 257 258 // Error implements the Error interface for ServerErrorMaxRefExceeded 259 func (e ServerErrorMaxRefExceeded) Error() string { 260 if e.Msg == "" { 261 return "Server: maximum allowed number of references exceeded" 262 } 263 return "ServerErrorMaxRefExceeded{" + e.Msg + "}" 264 } 265 266 // ServerErrorThrottle is returned when the server wants the client to backoff. 267 type ServerErrorThrottle struct { 268 Msg string 269 } 270 271 // Error implements the Error interface for ServerErrorThrottle. 272 func (e ServerErrorThrottle) Error() string { 273 return "ServerErrorThrottle{" + e.Msg + "}" 274 } 275 276 // ToStatus implements the ExportableError interface for ServerErrorThrottle. 277 func (e ServerErrorThrottle) ToStatus() (s keybase1.Status) { 278 s.Code = StatusCodeServerErrorThrottle 279 s.Name = "ERROR_THROTTLE" 280 s.Desc = e.Msg 281 return 282 } 283 284 // ServerErrorUnwrapper unwraps errors from a remote block server. 285 type ServerErrorUnwrapper struct{} 286 287 var _ rpc.ErrorUnwrapper = ServerErrorUnwrapper{} 288 289 // MakeArg implements rpc.ErrorUnwrapper. 290 func (eu ServerErrorUnwrapper) MakeArg() interface{} { 291 return &keybase1.Status{} 292 } 293 294 // UnwrapError implements rpc.ErrorUnwrapper. 295 func (eu ServerErrorUnwrapper) UnwrapError(arg interface{}) (appError error, dispatchError error) { 296 s, ok := arg.(*keybase1.Status) 297 if !ok { 298 return nil, errors.New("Error converting arg to keybase1.Status object in ServerErrorUnwrapper.UnwrapError") 299 } 300 301 if s == nil || s.Code == 0 { 302 return nil, nil 303 } 304 305 switch s.Code { 306 case StatusCodeServerError: 307 appError = ServerError{Msg: s.Desc} 308 case StatusCodeServerErrorBadRequest: 309 appError = ServerErrorBadRequest{Msg: s.Desc} 310 case StatusCodeServerErrorUnauthorized: 311 appError = ServerErrorUnauthorized{Msg: s.Desc} 312 case StatusCodeServerErrorOverQuota: 313 quotaErr := ServerErrorOverQuota{Msg: s.Desc} 314 for _, f := range s.Fields { 315 switch { 316 case f.Key == "QUOTA_USAGE": 317 quotaErr.Usage, _ = strconv.ParseInt(f.Value, 10, 64) 318 case f.Key == "QUOTA_LIMIT": 319 quotaErr.Limit, _ = strconv.ParseInt(f.Value, 10, 64) 320 case f.Key == "QUOTA_THROTTLE": 321 quotaErr.Throttled, _ = strconv.ParseBool(f.Value) 322 } 323 } 324 appError = quotaErr 325 case StatusCodeServerErrorBlockNonExistent: 326 appError = ServerErrorBlockNonExistent{Msg: s.Desc} 327 case StatusCodeServerErrorBlockArchived: 328 appError = ServerErrorBlockArchived{Msg: s.Desc} 329 case StatusCodeServerErrorNoPermission: 330 appError = ServerErrorNoPermission{Msg: s.Desc} 331 case StatusCodeServerErrorThrottle: 332 appError = ServerErrorThrottle{Msg: s.Desc} 333 case StatusCodeServerErrorBlockDeleted: 334 appError = ServerErrorBlockDeleted{Msg: s.Desc} 335 case StatusCodeServerErrorNonceNonExistent: 336 appError = ServerErrorNonceNonExistent{Msg: s.Desc} 337 case StatusCodeServerErrorMaxRefExceeded: 338 appError = ServerErrorMaxRefExceeded{Msg: s.Desc} 339 default: 340 ase := libkb.AppStatusError{ 341 Code: s.Code, 342 Name: s.Name, 343 Desc: s.Desc, 344 Fields: make(map[string]string), 345 } 346 for _, f := range s.Fields { 347 ase.Fields[f.Key] = f.Value 348 } 349 appError = ase 350 } 351 352 return appError, nil 353 } 354 355 // IsThrottleError returns whether or not the given error signals 356 // throttling. 357 func IsThrottleError(err error) bool { 358 if _, ok := err.(ServerErrorThrottle); ok { 359 return true 360 } 361 if quotaErr, ok := err.(ServerErrorOverQuota); ok && quotaErr.Throttled { 362 return true 363 } 364 return false 365 }