1package jsonrpc 2 3import ( 4 "bytes" 5 "io" 6 "io/ioutil" 7 "net/http" 8 "strings" 9 10 "github.com/aws/aws-sdk-go/aws/awserr" 11 "github.com/aws/aws-sdk-go/aws/request" 12 "github.com/aws/aws-sdk-go/private/protocol" 13 "github.com/aws/aws-sdk-go/private/protocol/json/jsonutil" 14) 15 16// UnmarshalTypedError provides unmarshaling errors API response errors 17// for both typed and untyped errors. 18type UnmarshalTypedError struct { 19 exceptions map[string]func(protocol.ResponseMetadata) error 20} 21 22// NewUnmarshalTypedError returns an UnmarshalTypedError initialized for the 23// set of exception names to the error unmarshalers 24func NewUnmarshalTypedError(exceptions map[string]func(protocol.ResponseMetadata) error) *UnmarshalTypedError { 25 return &UnmarshalTypedError{ 26 exceptions: exceptions, 27 } 28} 29 30// UnmarshalError attempts to unmarshal the HTTP response error as a known 31// error type. If unable to unmarshal the error type, the generic SDK error 32// type will be used. 33func (u *UnmarshalTypedError) UnmarshalError( 34 resp *http.Response, 35 respMeta protocol.ResponseMetadata, 36) (error, error) { 37 38 var buf bytes.Buffer 39 var jsonErr jsonErrorResponse 40 teeReader := io.TeeReader(resp.Body, &buf) 41 err := jsonutil.UnmarshalJSONError(&jsonErr, teeReader) 42 if err != nil { 43 return nil, err 44 } 45 body := ioutil.NopCloser(&buf) 46 47 // Code may be separated by hash(#), with the last element being the code 48 // used by the SDK. 49 codeParts := strings.SplitN(jsonErr.Code, "#", 2) 50 code := codeParts[len(codeParts)-1] 51 msg := jsonErr.Message 52 53 if fn, ok := u.exceptions[code]; ok { 54 // If exception code is know, use associated constructor to get a value 55 // for the exception that the JSON body can be unmarshaled into. 56 v := fn(respMeta) 57 err := jsonutil.UnmarshalJSONCaseInsensitive(v, body) 58 if err != nil { 59 return nil, err 60 } 61 62 return v, nil 63 } 64 65 // fallback to unmodeled generic exceptions 66 return awserr.NewRequestFailure( 67 awserr.New(code, msg, nil), 68 respMeta.StatusCode, 69 respMeta.RequestID, 70 ), nil 71} 72 73// UnmarshalErrorHandler is a named request handler for unmarshaling jsonrpc 74// protocol request errors 75var UnmarshalErrorHandler = request.NamedHandler{ 76 Name: "awssdk.jsonrpc.UnmarshalError", 77 Fn: UnmarshalError, 78} 79 80// UnmarshalError unmarshals an error response for a JSON RPC service. 81func UnmarshalError(req *request.Request) { 82 defer req.HTTPResponse.Body.Close() 83 84 var jsonErr jsonErrorResponse 85 err := jsonutil.UnmarshalJSONError(&jsonErr, req.HTTPResponse.Body) 86 if err != nil { 87 req.Error = awserr.NewRequestFailure( 88 awserr.New(request.ErrCodeSerialization, 89 "failed to unmarshal error message", err), 90 req.HTTPResponse.StatusCode, 91 req.RequestID, 92 ) 93 return 94 } 95 96 codes := strings.SplitN(jsonErr.Code, "#", 2) 97 req.Error = awserr.NewRequestFailure( 98 awserr.New(codes[len(codes)-1], jsonErr.Message, nil), 99 req.HTTPResponse.StatusCode, 100 req.RequestID, 101 ) 102} 103 104type jsonErrorResponse struct { 105 Code string `json:"__type"` 106 Message string `json:"message"` 107} 108