aboutsummaryrefslogtreecommitdiffstats
path: root/vendor/github.com/Azure/go-autorest/autorest/responder.go
diff options
context:
space:
mode:
Diffstat (limited to 'vendor/github.com/Azure/go-autorest/autorest/responder.go')
-rw-r--r--vendor/github.com/Azure/go-autorest/autorest/responder.go236
1 files changed, 236 insertions, 0 deletions
diff --git a/vendor/github.com/Azure/go-autorest/autorest/responder.go b/vendor/github.com/Azure/go-autorest/autorest/responder.go
new file mode 100644
index 000000000..87f71e585
--- /dev/null
+++ b/vendor/github.com/Azure/go-autorest/autorest/responder.go
@@ -0,0 +1,236 @@
+package autorest
+
+import (
+ "bytes"
+ "encoding/json"
+ "encoding/xml"
+ "fmt"
+ "io"
+ "io/ioutil"
+ "net/http"
+ "strings"
+)
+
+// Responder is the interface that wraps the Respond method.
+//
+// Respond accepts and reacts to an http.Response. Implementations must ensure to not share or hold
+// state since Responders may be shared and re-used.
+type Responder interface {
+ Respond(*http.Response) error
+}
+
+// ResponderFunc is a method that implements the Responder interface.
+type ResponderFunc func(*http.Response) error
+
+// Respond implements the Responder interface on ResponderFunc.
+func (rf ResponderFunc) Respond(r *http.Response) error {
+ return rf(r)
+}
+
+// RespondDecorator takes and possibly decorates, by wrapping, a Responder. Decorators may react to
+// the http.Response and pass it along or, first, pass the http.Response along then react.
+type RespondDecorator func(Responder) Responder
+
+// CreateResponder creates, decorates, and returns a Responder. Without decorators, the returned
+// Responder returns the passed http.Response unmodified. Responders may or may not be safe to share
+// and re-used: It depends on the applied decorators. For example, a standard decorator that closes
+// the response body is fine to share whereas a decorator that reads the body into a passed struct
+// is not.
+//
+// To prevent memory leaks, ensure that at least one Responder closes the response body.
+func CreateResponder(decorators ...RespondDecorator) Responder {
+ return DecorateResponder(
+ Responder(ResponderFunc(func(r *http.Response) error { return nil })),
+ decorators...)
+}
+
+// DecorateResponder accepts a Responder and a, possibly empty, set of RespondDecorators, which it
+// applies to the Responder. Decorators are applied in the order received, but their affect upon the
+// request depends on whether they are a pre-decorator (react to the http.Response and then pass it
+// along) or a post-decorator (pass the http.Response along and then react).
+func DecorateResponder(r Responder, decorators ...RespondDecorator) Responder {
+ for _, decorate := range decorators {
+ r = decorate(r)
+ }
+ return r
+}
+
+// Respond accepts an http.Response and a, possibly empty, set of RespondDecorators.
+// It creates a Responder from the decorators it then applies to the passed http.Response.
+func Respond(r *http.Response, decorators ...RespondDecorator) error {
+ if r == nil {
+ return nil
+ }
+ return CreateResponder(decorators...).Respond(r)
+}
+
+// ByIgnoring returns a RespondDecorator that ignores the passed http.Response passing it unexamined
+// to the next RespondDecorator.
+func ByIgnoring() RespondDecorator {
+ return func(r Responder) Responder {
+ return ResponderFunc(func(resp *http.Response) error {
+ return r.Respond(resp)
+ })
+ }
+}
+
+// ByCopying copies the contents of the http.Response Body into the passed bytes.Buffer as
+// the Body is read.
+func ByCopying(b *bytes.Buffer) RespondDecorator {
+ return func(r Responder) Responder {
+ return ResponderFunc(func(resp *http.Response) error {
+ err := r.Respond(resp)
+ if err == nil && resp != nil && resp.Body != nil {
+ resp.Body = TeeReadCloser(resp.Body, b)
+ }
+ return err
+ })
+ }
+}
+
+// ByDiscardingBody returns a RespondDecorator that first invokes the passed Responder after which
+// it copies the remaining bytes (if any) in the response body to ioutil.Discard. Since the passed
+// Responder is invoked prior to discarding the response body, the decorator may occur anywhere
+// within the set.
+func ByDiscardingBody() RespondDecorator {
+ return func(r Responder) Responder {
+ return ResponderFunc(func(resp *http.Response) error {
+ err := r.Respond(resp)
+ if err == nil && resp != nil && resp.Body != nil {
+ if _, err := io.Copy(ioutil.Discard, resp.Body); err != nil {
+ return fmt.Errorf("Error discarding the response body: %v", err)
+ }
+ }
+ return err
+ })
+ }
+}
+
+// ByClosing returns a RespondDecorator that first invokes the passed Responder after which it
+// closes the response body. Since the passed Responder is invoked prior to closing the response
+// body, the decorator may occur anywhere within the set.
+func ByClosing() RespondDecorator {
+ return func(r Responder) Responder {
+ return ResponderFunc(func(resp *http.Response) error {
+ err := r.Respond(resp)
+ if resp != nil && resp.Body != nil {
+ if err := resp.Body.Close(); err != nil {
+ return fmt.Errorf("Error closing the response body: %v", err)
+ }
+ }
+ return err
+ })
+ }
+}
+
+// ByClosingIfError returns a RespondDecorator that first invokes the passed Responder after which
+// it closes the response if the passed Responder returns an error and the response body exists.
+func ByClosingIfError() RespondDecorator {
+ return func(r Responder) Responder {
+ return ResponderFunc(func(resp *http.Response) error {
+ err := r.Respond(resp)
+ if err != nil && resp != nil && resp.Body != nil {
+ if err := resp.Body.Close(); err != nil {
+ return fmt.Errorf("Error closing the response body: %v", err)
+ }
+ }
+ return err
+ })
+ }
+}
+
+// ByUnmarshallingJSON returns a RespondDecorator that decodes a JSON document returned in the
+// response Body into the value pointed to by v.
+func ByUnmarshallingJSON(v interface{}) RespondDecorator {
+ return func(r Responder) Responder {
+ return ResponderFunc(func(resp *http.Response) error {
+ err := r.Respond(resp)
+ if err == nil {
+ b, errInner := ioutil.ReadAll(resp.Body)
+ // Some responses might include a BOM, remove for successful unmarshalling
+ b = bytes.TrimPrefix(b, []byte("\xef\xbb\xbf"))
+ if errInner != nil {
+ err = fmt.Errorf("Error occurred reading http.Response#Body - Error = '%v'", errInner)
+ } else if len(strings.Trim(string(b), " ")) > 0 {
+ errInner = json.Unmarshal(b, v)
+ if errInner != nil {
+ err = fmt.Errorf("Error occurred unmarshalling JSON - Error = '%v' JSON = '%s'", errInner, string(b))
+ }
+ }
+ }
+ return err
+ })
+ }
+}
+
+// ByUnmarshallingXML returns a RespondDecorator that decodes a XML document returned in the
+// response Body into the value pointed to by v.
+func ByUnmarshallingXML(v interface{}) RespondDecorator {
+ return func(r Responder) Responder {
+ return ResponderFunc(func(resp *http.Response) error {
+ err := r.Respond(resp)
+ if err == nil {
+ b, errInner := ioutil.ReadAll(resp.Body)
+ if errInner != nil {
+ err = fmt.Errorf("Error occurred reading http.Response#Body - Error = '%v'", errInner)
+ } else {
+ errInner = xml.Unmarshal(b, v)
+ if errInner != nil {
+ err = fmt.Errorf("Error occurred unmarshalling Xml - Error = '%v' Xml = '%s'", errInner, string(b))
+ }
+ }
+ }
+ return err
+ })
+ }
+}
+
+// WithErrorUnlessStatusCode returns a RespondDecorator that emits an error unless the response
+// StatusCode is among the set passed. On error, response body is fully read into a buffer and
+// presented in the returned error, as well as in the response body.
+func WithErrorUnlessStatusCode(codes ...int) RespondDecorator {
+ return func(r Responder) Responder {
+ return ResponderFunc(func(resp *http.Response) error {
+ err := r.Respond(resp)
+ if err == nil && !ResponseHasStatusCode(resp, codes...) {
+ derr := NewErrorWithResponse("autorest", "WithErrorUnlessStatusCode", resp, "%v %v failed with %s",
+ resp.Request.Method,
+ resp.Request.URL,
+ resp.Status)
+ if resp.Body != nil {
+ defer resp.Body.Close()
+ b, _ := ioutil.ReadAll(resp.Body)
+ derr.ServiceError = b
+ resp.Body = ioutil.NopCloser(bytes.NewReader(b))
+ }
+ err = derr
+ }
+ return err
+ })
+ }
+}
+
+// WithErrorUnlessOK returns a RespondDecorator that emits an error if the response StatusCode is
+// anything other than HTTP 200.
+func WithErrorUnlessOK() RespondDecorator {
+ return WithErrorUnlessStatusCode(http.StatusOK)
+}
+
+// ExtractHeader extracts all values of the specified header from the http.Response. It returns an
+// empty string slice if the passed http.Response is nil or the header does not exist.
+func ExtractHeader(header string, resp *http.Response) []string {
+ if resp != nil && resp.Header != nil {
+ return resp.Header[http.CanonicalHeaderKey(header)]
+ }
+ return nil
+}
+
+// ExtractHeaderValue extracts the first value of the specified header from the http.Response. It
+// returns an empty string if the passed http.Response is nil or the header does not exist.
+func ExtractHeaderValue(header string, resp *http.Response) string {
+ h := ExtractHeader(header, resp)
+ if len(h) > 0 {
+ return h[0]
+ }
+ return ""
+}