]>
Commit | Line | Data |
---|---|---|
bae9f6d2 JC |
1 | package s3 |
2 | ||
3 | import ( | |
4 | "encoding/xml" | |
5 | "fmt" | |
6 | "io" | |
7 | "io/ioutil" | |
8 | "net/http" | |
9 | "strings" | |
10 | ||
11 | "github.com/aws/aws-sdk-go/aws" | |
12 | "github.com/aws/aws-sdk-go/aws/awserr" | |
13 | "github.com/aws/aws-sdk-go/aws/request" | |
14 | ) | |
15 | ||
16 | type xmlErrorResponse struct { | |
17 | XMLName xml.Name `xml:"Error"` | |
18 | Code string `xml:"Code"` | |
19 | Message string `xml:"Message"` | |
20 | } | |
21 | ||
22 | func unmarshalError(r *request.Request) { | |
23 | defer r.HTTPResponse.Body.Close() | |
24 | defer io.Copy(ioutil.Discard, r.HTTPResponse.Body) | |
25 | ||
bae9f6d2 JC |
26 | // Bucket exists in a different region, and request needs |
27 | // to be made to the correct region. | |
28 | if r.HTTPResponse.StatusCode == http.StatusMovedPermanently { | |
107c1cdb ND |
29 | msg := fmt.Sprintf( |
30 | "incorrect region, the bucket is not in '%s' region at endpoint '%s'", | |
31 | aws.StringValue(r.Config.Region), | |
32 | aws.StringValue(r.Config.Endpoint), | |
33 | ) | |
34 | if v := r.HTTPResponse.Header.Get("x-amz-bucket-region"); len(v) != 0 { | |
35 | msg += fmt.Sprintf(", bucket is in '%s' region", v) | |
bae9f6d2 | 36 | } |
107c1cdb ND |
37 | r.Error = awserr.NewRequestFailure( |
38 | awserr.New("BucketRegionError", msg, nil), | |
39 | r.HTTPResponse.StatusCode, | |
40 | r.RequestID, | |
41 | ) | |
bae9f6d2 JC |
42 | return |
43 | } | |
44 | ||
45 | var errCode, errMsg string | |
46 | ||
47 | // Attempt to parse error from body if it is known | |
48 | resp := &xmlErrorResponse{} | |
49 | err := xml.NewDecoder(r.HTTPResponse.Body).Decode(resp) | |
50 | if err != nil && err != io.EOF { | |
51 | errCode = "SerializationError" | |
52 | errMsg = "failed to decode S3 XML error response" | |
53 | } else { | |
54 | errCode = resp.Code | |
55 | errMsg = resp.Message | |
56 | err = nil | |
57 | } | |
58 | ||
59 | // Fallback to status code converted to message if still no error code | |
60 | if len(errCode) == 0 { | |
61 | statusText := http.StatusText(r.HTTPResponse.StatusCode) | |
62 | errCode = strings.Replace(statusText, " ", "", -1) | |
63 | errMsg = statusText | |
64 | } | |
65 | ||
107c1cdb ND |
66 | r.Error = awserr.NewRequestFailure( |
67 | awserr.New(errCode, errMsg, err), | |
68 | r.HTTPResponse.StatusCode, | |
69 | r.RequestID, | |
70 | ) | |
bae9f6d2 JC |
71 | } |
72 | ||
73 | // A RequestFailure provides access to the S3 Request ID and Host ID values | |
74 | // returned from API operation errors. Getting the error as a string will | |
75 | // return the formated error with the same information as awserr.RequestFailure, | |
76 | // while also adding the HostID value from the response. | |
77 | type RequestFailure interface { | |
78 | awserr.RequestFailure | |
79 | ||
80 | // Host ID is the S3 Host ID needed for debug, and contacting support | |
81 | HostID() string | |
82 | } |