1package s3shared 2 3import ( 4 "encoding/xml" 5 "fmt" 6 "io" 7 "net/http" 8 "strings" 9) 10 11// ErrorComponents represents the error response fields 12// that will be deserialized from an xml error response body 13type ErrorComponents struct { 14 Code string `xml:"Code"` 15 Message string `xml:"Message"` 16 RequestID string `xml:"RequestId"` 17 HostID string `xml:"HostId"` 18} 19 20// GetUnwrappedErrorResponseComponents returns the error fields from an xml error response body 21func GetUnwrappedErrorResponseComponents(r io.Reader) (ErrorComponents, error) { 22 var errComponents ErrorComponents 23 if err := xml.NewDecoder(r).Decode(&errComponents); err != nil && err != io.EOF { 24 return ErrorComponents{}, fmt.Errorf("error while deserializing xml error response : %w", err) 25 } 26 return errComponents, nil 27} 28 29// GetWrappedErrorResponseComponents returns the error fields from an xml error response body 30// in which error code, and message are wrapped by a <Error> tag 31func GetWrappedErrorResponseComponents(r io.Reader) (ErrorComponents, error) { 32 var errComponents struct { 33 Code string `xml:"Error>Code"` 34 Message string `xml:"Error>Message"` 35 RequestID string `xml:"RequestId"` 36 HostID string `xml:"HostId"` 37 } 38 39 if err := xml.NewDecoder(r).Decode(&errComponents); err != nil && err != io.EOF { 40 return ErrorComponents{}, fmt.Errorf("error while deserializing xml error response : %w", err) 41 } 42 43 return ErrorComponents{ 44 Code: errComponents.Code, 45 Message: errComponents.Message, 46 RequestID: errComponents.RequestID, 47 HostID: errComponents.HostID, 48 }, nil 49} 50 51// GetErrorResponseComponents retrieves error components according to passed in options 52func GetErrorResponseComponents(r io.Reader, options ErrorResponseDeserializerOptions) (ErrorComponents, error) { 53 var errComponents ErrorComponents 54 var err error 55 56 if options.IsWrappedWithErrorTag { 57 errComponents, err = GetWrappedErrorResponseComponents(r) 58 } else { 59 errComponents, err = GetUnwrappedErrorResponseComponents(r) 60 } 61 62 if err != nil { 63 return ErrorComponents{}, err 64 } 65 66 // If an error code or message is not retrieved, it is derived from the http status code 67 // eg, for S3 service, we derive err code and message, if none is found 68 if options.UseStatusCode && len(errComponents.Code) == 0 && 69 len(errComponents.Message) == 0 { 70 // derive code and message from status code 71 statusText := http.StatusText(options.StatusCode) 72 errComponents.Code = strings.Replace(statusText, " ", "", -1) 73 errComponents.Message = statusText 74 } 75 return errComponents, nil 76} 77 78// ErrorResponseDeserializerOptions represents error response deserializer options for s3 and s3-control service 79type ErrorResponseDeserializerOptions struct { 80 // UseStatusCode denotes if status code should be used to retrieve error code, msg 81 UseStatusCode bool 82 83 // StatusCode is status code of error response 84 StatusCode int 85 86 //IsWrappedWithErrorTag represents if error response's code, msg is wrapped within an 87 // additional <Error> tag 88 IsWrappedWithErrorTag bool 89} 90