Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

private/protocol/query: Add parsing of ServiceUnavailableException #596

Merged
merged 1 commit into from
Mar 17, 2016
Merged
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
38 changes: 32 additions & 6 deletions private/protocol/query/unmarshal_error.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ package query

import (
"encoding/xml"
"io"
"io/ioutil"

"github.com/aws/aws-sdk-go/aws/awserr"
"github.com/aws/aws-sdk-go/aws/request"
Expand All @@ -15,18 +15,27 @@ type xmlErrorResponse struct {
RequestID string `xml:"RequestId"`
}

type xmlServiceUnavailableResponse struct {
XMLName xml.Name `xml:"ServiceUnavailableException"`
}

// UnmarshalErrorHandler is a name request handler to unmarshal request errors
var UnmarshalErrorHandler = request.NamedHandler{Name: "awssdk.query.UnmarshalError", Fn: UnmarshalError}

// UnmarshalError unmarshals an error response for an AWS Query service.
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 {
r.Error = awserr.New("SerializationError", "failed to decode query XML error response", err)
} else {
bodyBytes, err := ioutil.ReadAll(r.HTTPResponse.Body)
if err != nil {
r.Error = awserr.New("SerializationError", "failed to read from query HTTP response body", err)
return
}

// First check for specific error
resp := xmlErrorResponse{}
decodeErr := xml.Unmarshal(bodyBytes, &resp)
if decodeErr == nil {
reqID := resp.RequestID
if reqID == "" {
reqID = r.RequestID
Expand All @@ -36,5 +45,22 @@ func UnmarshalError(r *request.Request) {
r.HTTPResponse.StatusCode,
reqID,
)
return
}

// Check for unhandled error
servUnavailResp := xmlServiceUnavailableResponse{}
unavailErr := xml.Unmarshal(bodyBytes, &servUnavailResp)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Wouldn't it be possible to just update

type xmlErrorResponse struct {
    XMLName   xml.Name `xml:"ErrorResponse,ServiceUnavailableException"`
    Code      string   `xml:"Error>Code"`
    Message   string   `xml:"Error>Message"`
    RequestID string   `xml:"RequestId"`
}

then check the name rather than unmarshal twice?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Interesting didn't know you could do that with XML tags, ServiceUnavailableException isn't an attribute, but a different xml tag than ErrorResponse.

I'm not sure if xml can do that. I didn't see any mention of it in the godoc, and this play example hits an error, http://play.golang.org/p/NCECBedwc5

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You are right. We could just get rid of the ErrorResponse and ServiceUnavailableException and just check the name that way? But I don't know if I like that, what do you think?

Other than that, :shipit:!

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Removing the name tag all together might work if the only tags were ErrorResponse or ServiceUnavailableException i think. If there were any other tag before the two error tags that we are expecting I think the xml will not unmarshal the error we're actually looking for. The additional unmarshal should be an extremely rare event and only occurs if ErrorResponse failed to parse the error body.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Okay, thanks for the clarification. LGTM

if unavailErr == nil {
r.Error = awserr.NewRequestFailure(
awserr.New("ServiceUnavailableException", "service is unavailable", nil),
r.HTTPResponse.StatusCode,
r.RequestID,
)
return
}

// Failed to retrieve any error message from the response body
r.Error = awserr.New("SerializationError",
"failed to decode query XML error response", decodeErr)
}