Skip to content

Commit

Permalink
private/protocol: wrapping serialization errors (aws#2135)
Browse files Browse the repository at this point in the history
* serialization errors will now be wrapped as a request failure error if a serialization error occurred during unmarshaling

* adding request ID to request failure errors
  • Loading branch information
xibz authored and Igor Ch committed Sep 23, 2018
1 parent f735ad5 commit 6fff8d5
Show file tree
Hide file tree
Showing 7 changed files with 181 additions and 15 deletions.
12 changes: 10 additions & 2 deletions private/protocol/ec2query/unmarshal.go
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,11 @@ func Unmarshal(r *request.Request) {
decoder := xml.NewDecoder(r.HTTPResponse.Body)
err := xmlutil.UnmarshalXML(r.Data, decoder, "")
if err != nil {
r.Error = awserr.New("SerializationError", "failed decoding EC2 Query response", err)
r.Error = awserr.NewRequestFailure(
awserr.New("SerializationError", "failed decoding EC2 Query response", err),
r.HTTPResponse.StatusCode,
r.RequestID,
)
return
}
}
Expand All @@ -52,7 +56,11 @@ func UnmarshalError(r *request.Request) {
resp := &xmlErrorResponse{}
err := xml.NewDecoder(r.HTTPResponse.Body).Decode(resp)
if err != nil && err != io.EOF {
r.Error = awserr.New("SerializationError", "failed decoding EC2 Query error response", err)
r.Error = awserr.NewRequestFailure(
awserr.New("SerializationError", "failed decoding EC2 Query error response", err),
r.HTTPResponse.StatusCode,
r.RequestID,
)
} else {
r.Error = awserr.NewRequestFailure(
awserr.New(resp.Code, resp.Message, nil),
Expand Down
20 changes: 16 additions & 4 deletions private/protocol/jsonrpc/jsonrpc.go
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,11 @@ func Unmarshal(req *request.Request) {
if req.DataFilled() {
err := jsonutil.UnmarshalJSON(req.Data, req.HTTPResponse.Body)
if err != nil {
req.Error = awserr.New("SerializationError", "failed decoding JSON RPC response", err)
req.Error = awserr.NewRequestFailure(
awserr.New("SerializationError", "failed decoding JSON RPC response", err),
req.HTTPResponse.StatusCode,
req.RequestID,
)
}
}
return
Expand All @@ -80,20 +84,28 @@ func UnmarshalError(req *request.Request) {
defer req.HTTPResponse.Body.Close()
bodyBytes, err := ioutil.ReadAll(req.HTTPResponse.Body)
if err != nil {
req.Error = awserr.New("SerializationError", "failed reading JSON RPC error response", err)
req.Error = awserr.NewRequestFailure(
awserr.New("SerializationError", "failed reading JSON RPC error response", err),
req.HTTPResponse.StatusCode,
req.RequestID,
)
return
}
if len(bodyBytes) == 0 {
req.Error = awserr.NewRequestFailure(
awserr.New("SerializationError", req.HTTPResponse.Status, nil),
req.HTTPResponse.StatusCode,
"",
req.RequestID,
)
return
}
var jsonErr jsonErrorResponse
if err := json.Unmarshal(bodyBytes, &jsonErr); err != nil {
req.Error = awserr.New("SerializationError", "failed decoding JSON RPC error response", err)
req.Error = awserr.NewRequestFailure(
awserr.New("SerializationError", "failed decoding JSON RPC error response", err),
req.HTTPResponse.StatusCode,
req.RequestID,
)
return
}

Expand Down
6 changes: 5 additions & 1 deletion private/protocol/query/unmarshal.go
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,11 @@ func Unmarshal(r *request.Request) {
decoder := xml.NewDecoder(r.HTTPResponse.Body)
err := xmlutil.UnmarshalXML(r.Data, decoder, r.Operation.Name+"Result")
if err != nil {
r.Error = awserr.New("SerializationError", "failed decoding Query response", err)
r.Error = awserr.NewRequestFailure(
awserr.New("SerializationError", "failed decoding Query response", err),
r.HTTPResponse.StatusCode,
r.RequestID,
)
return
}
}
Expand Down
14 changes: 11 additions & 3 deletions private/protocol/query/unmarshal_error.go
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,11 @@ func UnmarshalError(r *request.Request) {

bodyBytes, err := ioutil.ReadAll(r.HTTPResponse.Body)
if err != nil {
r.Error = awserr.New("SerializationError", "failed to read from query HTTP response body", err)
r.Error = awserr.NewRequestFailure(
awserr.New("SerializationError", "failed to read from query HTTP response body", err),
r.HTTPResponse.StatusCode,
r.RequestID,
)
return
}

Expand Down Expand Up @@ -61,6 +65,10 @@ func UnmarshalError(r *request.Request) {
}

// Failed to retrieve any error message from the response body
r.Error = awserr.New("SerializationError",
"failed to decode query XML error response", decodeErr)
r.Error = awserr.NewRequestFailure(
awserr.New("SerializationError",
"failed to decode query XML error response", decodeErr),
r.HTTPResponse.StatusCode,
r.RequestID,
)
}
14 changes: 11 additions & 3 deletions private/protocol/restjson/restjson.go
Original file line number Diff line number Diff line change
Expand Up @@ -57,20 +57,28 @@ func UnmarshalError(r *request.Request) {
code := r.HTTPResponse.Header.Get("X-Amzn-Errortype")
bodyBytes, err := ioutil.ReadAll(r.HTTPResponse.Body)
if err != nil {
r.Error = awserr.New("SerializationError", "failed reading REST JSON error response", err)
r.Error = awserr.NewRequestFailure(
awserr.New("SerializationError", "failed reading REST JSON error response", err),
r.HTTPResponse.StatusCode,
r.RequestID,
)
return
}
if len(bodyBytes) == 0 {
r.Error = awserr.NewRequestFailure(
awserr.New("SerializationError", r.HTTPResponse.Status, nil),
r.HTTPResponse.StatusCode,
"",
r.RequestID,
)
return
}
var jsonErr jsonErrorResponse
if err := json.Unmarshal(bodyBytes, &jsonErr); err != nil {
r.Error = awserr.New("SerializationError", "failed decoding REST JSON error response", err)
r.Error = awserr.NewRequestFailure(
awserr.New("SerializationError", "failed decoding REST JSON error response", err),
r.HTTPResponse.StatusCode,
r.RequestID,
)
return
}

Expand Down
12 changes: 10 additions & 2 deletions private/protocol/restxml/restxml.go
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,11 @@ func Build(r *request.Request) {
var buf bytes.Buffer
err := xmlutil.BuildXML(r.Params, xml.NewEncoder(&buf))
if err != nil {
r.Error = awserr.New("SerializationError", "failed to encode rest XML request", err)
r.Error = awserr.NewRequestFailure(
awserr.New("SerializationError", "failed to encode rest XML request", err),
r.HTTPResponse.StatusCode,
r.RequestID,
)
return
}
r.SetBufferBody(buf.Bytes())
Expand All @@ -50,7 +54,11 @@ func Unmarshal(r *request.Request) {
decoder := xml.NewDecoder(r.HTTPResponse.Body)
err := xmlutil.UnmarshalXML(r.Data, decoder, "")
if err != nil {
r.Error = awserr.New("SerializationError", "failed to decode REST XML response", err)
r.Error = awserr.NewRequestFailure(
awserr.New("SerializationError", "failed to decode REST XML response", err),
r.HTTPResponse.StatusCode,
r.RequestID,
)
return
}
} else {
Expand Down
118 changes: 118 additions & 0 deletions private/protocol/unmarshal_test.go
Original file line number Diff line number Diff line change
@@ -1,12 +1,19 @@
package protocol_test

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

"github.com/aws/aws-sdk-go/aws/awserr"
"github.com/aws/aws-sdk-go/aws/request"
"github.com/aws/aws-sdk-go/private/protocol"
"github.com/aws/aws-sdk-go/private/protocol/ec2query"
"github.com/aws/aws-sdk-go/private/protocol/jsonrpc"
"github.com/aws/aws-sdk-go/private/protocol/query"
"github.com/aws/aws-sdk-go/private/protocol/restjson"
"github.com/aws/aws-sdk-go/private/protocol/restxml"
"github.com/stretchr/testify/assert"
)

Expand Down Expand Up @@ -38,3 +45,114 @@ func TestUnmarshalDrainBodyNoBody(t *testing.T) {
protocol.UnmarshalDiscardBody(r)
assert.NoError(t, r.Error)
}

func TestUnmarshalSeriaizationError(t *testing.T) {

type testOutput struct {
_ struct{}
}

cases := []struct {
name string
r request.Request
unmarshalFn func(*request.Request)
expectedError awserr.RequestFailure
}{
{
name: "jsonrpc",
r: request.Request{
Data: &testOutput{},
HTTPResponse: &http.Response{
StatusCode: 502,
Body: ioutil.NopCloser(strings.NewReader("invalid json")),
},
},
unmarshalFn: jsonrpc.Unmarshal,
expectedError: awserr.NewRequestFailure(
awserr.New("SerializationError", "", nil),
502,
"",
),
},
{
name: "ec2query",
r: request.Request{
Data: &testOutput{},
HTTPResponse: &http.Response{
StatusCode: 111,
Body: ioutil.NopCloser(strings.NewReader("<<>>>>>>")),
},
},
unmarshalFn: ec2query.Unmarshal,
expectedError: awserr.NewRequestFailure(
awserr.New("SerializationError", "", nil),
111,
"",
),
},
{
name: "query",
r: request.Request{
Operation: &request.Operation{
Name: "Foo",
},
Data: &testOutput{},
HTTPResponse: &http.Response{
StatusCode: 1,
Body: ioutil.NopCloser(strings.NewReader("<<>>>>>>")),
},
},
unmarshalFn: query.Unmarshal,
expectedError: awserr.NewRequestFailure(
awserr.New("SerializationError", "", nil),
1,
"",
),
},
{
name: "restjson",
r: request.Request{
Data: &testOutput{},
HTTPResponse: &http.Response{
StatusCode: 123,
Body: ioutil.NopCloser(strings.NewReader("invalid json")),
},
},
unmarshalFn: restjson.Unmarshal,
expectedError: awserr.NewRequestFailure(
awserr.New("SerializationError", "", nil),
123,
"",
),
},
{
name: "restxml",
r: request.Request{
Data: &testOutput{},
HTTPResponse: &http.Response{
StatusCode: 456,
Body: ioutil.NopCloser(strings.NewReader("<<>>>>>>")),
},
},
unmarshalFn: restxml.Unmarshal,
expectedError: awserr.NewRequestFailure(
awserr.New("SerializationError", "", nil),
456,
"",
),
},
}

for _, c := range cases {
c.unmarshalFn(&c.r)

rfErr, ok := c.r.Error.(awserr.RequestFailure)
if !ok {
t.Errorf("%s: expected awserr.RequestFailure, but received %T", c.name, c.r.Error)
}

if e, a := c.expectedError.StatusCode(), rfErr.StatusCode(); e != a {
t.Errorf("%s: expected %v, but received %v", c.name, e, a)
}
}
}

0 comments on commit 6fff8d5

Please sign in to comment.