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  }