1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107
|
package helpers
import (
"encoding/json"
"encoding/xml"
"fmt"
"io/ioutil"
"net/http"
"strings"
"github.com/Azure/go-autorest/autorest"
"github.com/Azure/go-autorest/autorest/azure"
)
// TODO: trial switching over to this, then upstream it
// WithErrorUnlessStatusCode returns a RespondDecorator that emits an
// azure.RequestError by reading the response body unless the response HTTP status code
// is among the set passed.
//
// If there is a chance service may return responses other than the Azure error
// format and the response cannot be parsed into an error, a decoding error will
// be returned containing the response body. In any case, the Responder will
// return an error if the status code is not satisfied.
//
// If this Responder returns an error, the response body will be replaced with
// an in-memory reader, which needs no further closing.
func WithErrorUnlessStatusCode(codes ...int) autorest.RespondDecorator {
return func(r autorest.Responder) autorest.Responder {
return autorest.ResponderFunc(func(resp *http.Response) error {
err := r.Respond(resp)
if err == nil && !autorest.ResponseHasStatusCode(resp, codes...) {
var e azure.RequestError
defer resp.Body.Close()
contentType := autorest.EncodedAsJSON
if resp != nil {
contentTypeStr := resp.Header.Get("Content-Type")
if strings.EqualFold(contentTypeStr, "application/xml") {
contentType = autorest.EncodedAsXML
}
}
// Copy and replace the Body in case it does not contain an error object.
// This will leave the Body available to the caller.
b, decodeErr := autorest.CopyAndDecode(contentType, resp.Body, &e)
resp.Body = ioutil.NopCloser(&b)
if decodeErr != nil {
return fmt.Errorf("autorest/azure: error response cannot be parsed: %q error: %v", b.String(), decodeErr)
}
if e.ServiceError == nil {
switch contentType {
case autorest.EncodedAsJSON:
// Check if error is unwrapped ServiceError
if err := json.Unmarshal(b.Bytes(), &e.ServiceError); err != nil {
return err
}
break
case autorest.EncodedAsXML:
// Check if error is unwrapped ServiceError
if err := xml.Unmarshal(b.Bytes(), &e.ServiceError); err != nil {
return err
}
break
}
}
if e.ServiceError.Message == "" {
rawBody := map[string]interface{}{}
switch contentType {
case autorest.EncodedAsJSON:
// if we're here it means the returned error wasn't OData v4 compliant.
// try to unmarshal the body as raw JSON in hopes of getting something.
if err := json.Unmarshal(b.Bytes(), &rawBody); err != nil {
return err
}
break
case autorest.EncodedAsXML:
// if we're here it means the returned error wasn't OData v4 compliant.
// try to unmarshal the body as raw XML in hopes of getting something.
if err := xml.Unmarshal(b.Bytes(), &rawBody); err != nil {
return err
}
break
}
e.ServiceError = &azure.ServiceError{
Code: "Unknown",
Message: "Unknown service error",
}
if len(rawBody) > 0 {
e.ServiceError.Details = []map[string]interface{}{rawBody}
}
}
e.Response = resp
e.RequestID = azure.ExtractRequestID(resp)
if e.StatusCode == nil {
e.StatusCode = resp.StatusCode
}
err = &e
}
return err
})
}
}
|