github.com/minio/madmin-go@v1.7.5/api-error-response.go (about) 1 // 2 // MinIO Object Storage (c) 2021 MinIO, Inc. 3 // 4 // Licensed under the Apache License, Version 2.0 (the "License"); 5 // you may not use this file except in compliance with the License. 6 // You may obtain a copy of the License at 7 // 8 // http://www.apache.org/licenses/LICENSE-2.0 9 // 10 // Unless required by applicable law or agreed to in writing, software 11 // distributed under the License is distributed on an "AS IS" BASIS, 12 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 // See the License for the specific language governing permissions and 14 // limitations under the License. 15 // 16 17 package madmin 18 19 import ( 20 "encoding/hex" 21 "encoding/json" 22 "encoding/xml" 23 "fmt" 24 "io" 25 "io/ioutil" 26 "net/http" 27 "unicode/utf8" 28 ) 29 30 /* **** SAMPLE ERROR RESPONSE **** 31 <?xml version="1.0" encoding="UTF-8"?> 32 <Error> 33 <Code>AccessDenied</Code> 34 <Message>Access Denied</Message> 35 <BucketName>bucketName</BucketName> 36 <Key>objectName</Key> 37 <RequestId>F19772218238A85A</RequestId> 38 <HostId>GuWkjyviSiGHizehqpmsD1ndz5NClSP19DOT+s2mv7gXGQ8/X1lhbDGiIJEXpGFD</HostId> 39 </Error> 40 */ 41 42 // ErrorResponse - Is the typed error returned by all API operations. 43 type ErrorResponse struct { 44 XMLName xml.Name `xml:"Error" json:"-"` 45 Code string 46 Message string 47 BucketName string 48 Key string 49 RequestID string `xml:"RequestId"` 50 HostID string `xml:"HostId"` 51 52 // Region where the bucket is located. This header is returned 53 // only in HEAD bucket and ListObjects response. 54 Region string 55 } 56 57 // Error - Returns HTTP error string 58 func (e ErrorResponse) Error() string { 59 return e.Message 60 } 61 62 const ( 63 reportIssue = "Please report this issue at https://github.com/minio/minio/issues." 64 ) 65 66 // httpRespToErrorResponse returns a new encoded ErrorResponse 67 // structure as error. 68 func httpRespToErrorResponse(resp *http.Response) error { 69 if resp == nil || resp.Body == nil { 70 msg := "Response is empty. " + reportIssue 71 return ErrInvalidArgument(msg) 72 } 73 74 defer closeResponse(resp) 75 // Limit to 100K 76 body, err := ioutil.ReadAll(io.LimitReader(resp.Body, 100<<10)) 77 if err != nil { 78 return ErrorResponse{ 79 Code: resp.Status, 80 Message: fmt.Sprintf("Failed to read server response: %s.", err), 81 } 82 } 83 84 var errResp ErrorResponse 85 // Decode the json error 86 err = json.Unmarshal(body, &errResp) 87 if err != nil { 88 // We might get errors as XML, try that. 89 xmlErr := xml.Unmarshal(body, &errResp) 90 91 if xmlErr != nil { 92 bodyString := string(body) 93 if !utf8.Valid(body) { 94 bodyString = hex.EncodeToString(body) 95 } 96 if len(bodyString) > 1024 { 97 bodyString = bodyString[:1021] + "..." 98 } 99 return ErrorResponse{ 100 Code: resp.Status, 101 Message: fmt.Sprintf("Failed to parse server response (%s): %s", err.Error(), bodyString), 102 } 103 } 104 } 105 return errResp 106 } 107 108 // ToErrorResponse - Returns parsed ErrorResponse struct from body and 109 // http headers. 110 // 111 // For example: 112 // 113 // import admin "github.com/minio/madmin-go" 114 // ... 115 // ... 116 // ss, err := adm.ServiceStatus(...) 117 // if err != nil { 118 // resp := admin.ToErrorResponse(err) 119 // } 120 // ... 121 func ToErrorResponse(err error) ErrorResponse { 122 switch err := err.(type) { 123 case ErrorResponse: 124 return err 125 default: 126 return ErrorResponse{} 127 } 128 } 129 130 // ErrInvalidArgument - Invalid argument response. 131 func ErrInvalidArgument(message string) error { 132 return ErrorResponse{ 133 Code: "InvalidArgument", 134 Message: message, 135 RequestID: "minio", 136 } 137 }