Skip to content
This repository was archived by the owner on Jul 31, 2025. It is now read-only.
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
23 changes: 21 additions & 2 deletions aws/awserr/error.go
Original file line number Diff line number Diff line change
Expand Up @@ -138,8 +138,27 @@ type RequestFailure interface {
RequestID() string
}

// NewRequestFailure returns a new request error wrapper for the given Error
// provided.
// NewRequestFailure returns a wrapped error with additional information for
// request status code, and service requestID.
//
// Should be used to wrap all request which involve service requests. Even if
// the request failed without a service response, but had an HTTP status code
// that may be meaningful.
func NewRequestFailure(err Error, statusCode int, reqID string) RequestFailure {
return newRequestError(err, statusCode, reqID)
}

// UnmarshalError provides the interface for the SDK failing to unmarshal data.
type UnmarshalError interface {
awsError
Bytes() []byte
}

// NewUnmarshalError returns an initialized UnmarshalError error wrapper adding
// the bytes that fail to unmarshal to the error.
func NewUnmarshalError(err error, msg string, bytes []byte) UnmarshalError {
return &unmarshalError{
awsError: New("UnmarshalError", msg, err),
bytes: bytes,
}
}
29 changes: 28 additions & 1 deletion aws/awserr/types.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
package awserr

import "fmt"
import (
"encoding/hex"
"fmt"
)

// SprintError returns a string of the formatted error code.
//
Expand Down Expand Up @@ -119,6 +122,7 @@ type requestError struct {
awsError
statusCode int
requestID string
bytes []byte
}

// newRequestError returns a wrapped error with additional information for
Expand Down Expand Up @@ -170,6 +174,29 @@ func (r requestError) OrigErrs() []error {
return []error{r.OrigErr()}
}

type unmarshalError struct {
awsError
bytes []byte
}

// Error returns the string representation of the error.
// Satisfies the error interface.
func (e unmarshalError) Error() string {
extra := hex.Dump(e.bytes)
return SprintError(e.Code(), e.Message(), extra, e.OrigErr())
}

// String returns the string representation of the error.
// Alias for Error to satisfy the stringer interface.
func (e unmarshalError) String() string {
return e.Error()
}

// Bytes returns the bytes that failed to unmarshal.
func (e unmarshalError) Bytes() []byte {
return e.bytes
}

// An error list that satisfies the golang interface
type errorList []error

Expand Down
6 changes: 4 additions & 2 deletions aws/credentials/ec2rolecreds/ec2_role_provider.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import (
"github.com/aws/aws-sdk-go/aws/client"
"github.com/aws/aws-sdk-go/aws/credentials"
"github.com/aws/aws-sdk-go/aws/ec2metadata"
"github.com/aws/aws-sdk-go/aws/request"
"github.com/aws/aws-sdk-go/internal/sdkuri"
)

Expand Down Expand Up @@ -142,7 +143,8 @@ func requestCredList(client *ec2metadata.EC2Metadata) ([]string, error) {
}

if err := s.Err(); err != nil {
return nil, awserr.New("SerializationError", "failed to read EC2 instance role from metadata service", err)
return nil, awserr.New(request.ErrCodeSerialization,
"failed to read EC2 instance role from metadata service", err)
}

return credsList, nil
Expand All @@ -164,7 +166,7 @@ func requestCred(client *ec2metadata.EC2Metadata, credsName string) (ec2RoleCred
respCreds := ec2RoleCredRespBody{}
if err := json.NewDecoder(strings.NewReader(resp)).Decode(&respCreds); err != nil {
return ec2RoleCredRespBody{},
awserr.New("SerializationError",
awserr.New(request.ErrCodeSerialization,
fmt.Sprintf("failed to decode %s EC2 instance role credentials", credsName),
err)
}
Expand Down
15 changes: 10 additions & 5 deletions aws/credentials/endpointcreds/provider.go
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@ import (
"github.com/aws/aws-sdk-go/aws/client/metadata"
"github.com/aws/aws-sdk-go/aws/credentials"
"github.com/aws/aws-sdk-go/aws/request"
"github.com/aws/aws-sdk-go/private/protocol/json/jsonutil"
)

// ProviderName is the name of the credentials provider.
Expand Down Expand Up @@ -174,7 +175,7 @@ func unmarshalHandler(r *request.Request) {

out := r.Data.(*getCredentialsOutput)
if err := json.NewDecoder(r.HTTPResponse.Body).Decode(&out); err != nil {
r.Error = awserr.New("SerializationError",
r.Error = awserr.New(request.ErrCodeSerialization,
"failed to decode endpoint credentials",
err,
)
Expand All @@ -185,11 +186,15 @@ func unmarshalError(r *request.Request) {
defer r.HTTPResponse.Body.Close()

var errOut errorOutput
if err := json.NewDecoder(r.HTTPResponse.Body).Decode(&errOut); err != nil {
r.Error = awserr.New("SerializationError",
"failed to decode endpoint credentials",
err,
err := jsonutil.UnmarshalJSONError(&errOut, r.HTTPResponse.Body)
if err != nil {
r.Error = awserr.NewRequestFailure(
awserr.New(request.ErrCodeSerialization,
"failed to decode error message", err),
r.HTTPResponse.StatusCode,
r.RequestID,
)
return
}

// Response body format is not consistent between metadata endpoints.
Expand Down
2 changes: 1 addition & 1 deletion aws/csm/reporter.go
Original file line number Diff line number Diff line change
Expand Up @@ -96,7 +96,7 @@ func getMetricException(err awserr.Error) metricException {

switch code {
case "RequestError",
"SerializationError",
request.ErrCodeSerialization,
request.CanceledErrorCode:
return sdkException{
requestException{exception: code, message: msg},
Expand Down
4 changes: 2 additions & 2 deletions aws/ec2metadata/api.go
Original file line number Diff line number Diff line change
Expand Up @@ -82,7 +82,7 @@ func (c *EC2Metadata) GetInstanceIdentityDocument() (EC2InstanceIdentityDocument
doc := EC2InstanceIdentityDocument{}
if err := json.NewDecoder(strings.NewReader(resp)).Decode(&doc); err != nil {
return EC2InstanceIdentityDocument{},
awserr.New("SerializationError",
awserr.New(request.ErrCodeSerialization,
"failed to decode EC2 instance identity document", err)
}

Expand All @@ -101,7 +101,7 @@ func (c *EC2Metadata) IAMInfo() (EC2IAMInfo, error) {
info := EC2IAMInfo{}
if err := json.NewDecoder(strings.NewReader(resp)).Decode(&info); err != nil {
return EC2IAMInfo{},
awserr.New("SerializationError",
awserr.New(request.ErrCodeSerialization,
"failed to decode EC2 IAM info", err)
}

Expand Down
4 changes: 2 additions & 2 deletions aws/ec2metadata/service.go
Original file line number Diff line number Diff line change
Expand Up @@ -123,7 +123,7 @@ func unmarshalHandler(r *request.Request) {
defer r.HTTPResponse.Body.Close()
b := &bytes.Buffer{}
if _, err := io.Copy(b, r.HTTPResponse.Body); err != nil {
r.Error = awserr.New("SerializationError", "unable to unmarshal EC2 metadata respose", err)
r.Error = awserr.New(request.ErrCodeSerialization, "unable to unmarshal EC2 metadata respose", err)
return
}

Expand All @@ -136,7 +136,7 @@ func unmarshalError(r *request.Request) {
defer r.HTTPResponse.Body.Close()
b := &bytes.Buffer{}
if _, err := io.Copy(b, r.HTTPResponse.Body); err != nil {
r.Error = awserr.New("SerializationError", "unable to unmarshal EC2 metadata error respose", err)
r.Error = awserr.New(request.ErrCodeSerialization, "unable to unmarshal EC2 metadata error respose", err)
return
}

Expand Down
4 changes: 2 additions & 2 deletions aws/request/request_1_11_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -71,9 +71,9 @@ func TestSerializationErrConnectionReset_read(t *testing.T) {
req.ApplyOptions(request.WithResponseReadTimeout(time.Second))
err := req.Send()
if err == nil {
t.Error("Expected rror 'SerializationError', but received nil")
t.Error("Expected error 'SerializationError', but received nil")
}
if aerr, ok := err.(awserr.Error); ok && aerr.Code() != "SerializationError" {
if aerr, ok := err.(awserr.Error); ok && aerr.Code() != request.ErrCodeSerialization {
t.Errorf("Expected 'SerializationError', but received %q", aerr.Code())
} else if !ok {
t.Errorf("Expected 'awserr.Error', but received %v", reflect.TypeOf(err))
Expand Down
4 changes: 2 additions & 2 deletions aws/request/request_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -675,9 +675,9 @@ func TestSerializationErrConnectionReset_accept(t *testing.T) {
req.ApplyOptions(request.WithResponseReadTimeout(time.Second))
err := req.Send()
if err == nil {
t.Error("Expected rror 'SerializationError', but received nil")
t.Error("Expected error 'SerializationError', but received nil")
}
if aerr, ok := err.(awserr.Error); ok && aerr.Code() != "SerializationError" {
if aerr, ok := err.(awserr.Error); ok && aerr.Code() != request.ErrCodeSerialization {
t.Errorf("Expected 'SerializationError', but received %q", aerr.Code())
} else if !ok {
t.Errorf("Expected 'awserr.Error', but received %v", reflect.TypeOf(err))
Expand Down
5 changes: 3 additions & 2 deletions example/service/dynamodb/transactWriteItems/error_handler.go
Original file line number Diff line number Diff line change
Expand Up @@ -45,14 +45,15 @@ func TxAwareUnmarshalError(req *request.Request) {
err := json.NewDecoder(req.HTTPResponse.Body).Decode(&jsonErr)
if err == io.EOF {
req.Error = awserr.NewRequestFailure(
awserr.New("SerializationError", req.HTTPResponse.Status, nil),
awserr.New(request.ErrCodeSerialization, req.HTTPResponse.Status, nil),
req.HTTPResponse.StatusCode,
req.RequestID,
)
return
} else if err != nil {
req.Error = awserr.NewRequestFailure(
awserr.New("SerializationError", "failed decoding JSON RPC error response", err),
awserr.New(request.ErrCodeSerialization,
"failed decoding JSON RPC error response", err),
req.HTTPResponse.StatusCode,
req.RequestID,
)
Expand Down
3 changes: 2 additions & 1 deletion private/protocol/ec2query/build.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,8 @@ func Build(r *request.Request) {
"Version": {r.ClientInfo.APIVersion},
}
if err := queryutil.Parse(body, r.Params, true); err != nil {
r.Error = awserr.New("SerializationError", "failed encoding EC2 Query request", err)
r.Error = awserr.New(request.ErrCodeSerialization,
"failed encoding EC2 Query request", err)
}

if !r.IsPresigned() {
Expand Down
32 changes: 19 additions & 13 deletions private/protocol/ec2query/unmarshal.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@ package ec2query

import (
"encoding/xml"
"io"

"github.com/aws/aws-sdk-go/aws/awserr"
"github.com/aws/aws-sdk-go/aws/request"
Expand All @@ -28,7 +27,8 @@ func Unmarshal(r *request.Request) {
err := xmlutil.UnmarshalXML(r.Data, decoder, "")
if err != nil {
r.Error = awserr.NewRequestFailure(
awserr.New("SerializationError", "failed decoding EC2 Query response", err),
awserr.New(request.ErrCodeSerialization,
"failed decoding EC2 Query response", err),
r.HTTPResponse.StatusCode,
r.RequestID,
)
Expand All @@ -39,7 +39,11 @@ func Unmarshal(r *request.Request) {

// UnmarshalMeta unmarshals response headers for the EC2 protocol.
func UnmarshalMeta(r *request.Request) {
// TODO implement unmarshaling of request IDs
r.RequestID = r.HTTPResponse.Header.Get("X-Amzn-Requestid")
if r.RequestID == "" {
// Alternative version of request id in the header
r.RequestID = r.HTTPResponse.Header.Get("X-Amz-Request-Id")
}
}

type xmlErrorResponse struct {
Expand All @@ -53,19 +57,21 @@ type xmlErrorResponse struct {
func UnmarshalError(r *request.Request) {
defer r.HTTPResponse.Body.Close()

resp := &xmlErrorResponse{}
err := xml.NewDecoder(r.HTTPResponse.Body).Decode(resp)
if err != nil && err != io.EOF {
var respErr xmlErrorResponse
err := xmlutil.UnmarshalXMLError(&respErr, r.HTTPResponse.Body)
if err != nil {
r.Error = awserr.NewRequestFailure(
awserr.New("SerializationError", "failed decoding EC2 Query error response", err),
awserr.New(request.ErrCodeSerialization,
"failed to unmarshal error message", err),
r.HTTPResponse.StatusCode,
r.RequestID,
)
} else {
r.Error = awserr.NewRequestFailure(
awserr.New(resp.Code, resp.Message, nil),
r.HTTPResponse.StatusCode,
resp.RequestID,
)
return
}

r.Error = awserr.NewRequestFailure(
awserr.New(respErr.Code, respErr.Message, nil),
r.HTTPResponse.StatusCode,
respErr.RequestID,
)
}
82 changes: 82 additions & 0 deletions private/protocol/ec2query/unmarshal_error_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
// +build go1.8

package ec2query

import (
"io/ioutil"
"net/http"
"strings"
"testing"

"github.com/aws/aws-sdk-go/aws/awserr"
"github.com/aws/aws-sdk-go/aws/request"
)

func TestUnmarshalError(t *testing.T) {
cases := map[string]struct {
Request *request.Request
Code, Msg string
ReqID string
Status int
}{
"ErrorResponse": {
Request: &request.Request{
HTTPResponse: &http.Response{
StatusCode: 400,
Header: http.Header{},
Body: ioutil.NopCloser(strings.NewReader(
`<Response>
<Errors>
<Error>
<Code>codeAbc</Code>
<Message>msg123</Message>
</Error>
</Errors>
<RequestID>reqID123</RequestID>
</Response>`)),
},
},
Code: "codeAbc", Msg: "msg123",
Status: 400, ReqID: "reqID123",
},
"unknown tag": {
Request: &request.Request{
HTTPResponse: &http.Response{
StatusCode: 400,
Header: http.Header{},
Body: ioutil.NopCloser(strings.NewReader(
`<Hello>
<World>.</World>
</Hello>`)),
},
},
Code: request.ErrCodeSerialization,
Msg: "failed to unmarshal error message",
Status: 400,
},
}

for name, c := range cases {
t.Run(name, func(t *testing.T) {
r := c.Request
UnmarshalError(r)
if r.Error == nil {
t.Fatalf("expect error, got none")
}

aerr := r.Error.(awserr.RequestFailure)
if e, a := c.Code, aerr.Code(); e != a {
t.Errorf("expect %v code, got %v", e, a)
}
if e, a := c.Msg, aerr.Message(); e != a {
t.Errorf("expect %q message, got %q", e, a)
}
if e, a := c.ReqID, aerr.RequestID(); e != a {
t.Errorf("expect %v request ID, got %v", e, a)
}
if e, a := c.Status, aerr.StatusCode(); e != a {
t.Errorf("expect %v status code, got %v", e, a)
}
})
}
}
Loading