~nskaggs/+junk/xenial-test

« back to all changes in this revision

Viewing changes to src/github.com/Azure/azure-sdk-for-go/Godeps/_workspace/src/github.com/Azure/go-autorest/autorest/client.go

  • Committer: Nicholas Skaggs
  • Date: 2016-10-24 20:56:05 UTC
  • Revision ID: nicholas.skaggs@canonical.com-20161024205605-z8lta0uvuhtxwzwl
Initi with beta15

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
package autorest
 
2
 
 
3
import (
 
4
        "bytes"
 
5
        "io"
 
6
        "io/ioutil"
 
7
        "log"
 
8
        "net/http"
 
9
        "time"
 
10
)
 
11
 
 
12
const (
 
13
        // DefaultPollingDelay is the default delay between polling requests (only used if the
 
14
        // http.Request lacks a well-formed Retry-After header).
 
15
        DefaultPollingDelay = 60 * time.Second
 
16
 
 
17
        // DefaultPollingDuration is the default total polling duration.
 
18
        DefaultPollingDuration = 15 * time.Minute
 
19
)
 
20
 
 
21
// PollingMode sets how, if at all, clients composed with Client will poll.
 
22
type PollingMode string
 
23
 
 
24
const (
 
25
        // PollUntilAttempts polling mode polls until reaching a maximum number of attempts.
 
26
        PollUntilAttempts PollingMode = "poll-until-attempts"
 
27
 
 
28
        // PollUntilDuration polling mode polls until a specified time.Duration has passed.
 
29
        PollUntilDuration PollingMode = "poll-until-duration"
 
30
 
 
31
        // DoNotPoll disables polling.
 
32
        DoNotPoll PollingMode = "not-at-all"
 
33
)
 
34
 
 
35
const (
 
36
        requestFormat = `HTTP Request Begin ===================================================
 
37
%s
 
38
===================================================== HTTP Request End
 
39
`
 
40
        responseFormat = `HTTP Response Begin ===================================================
 
41
%s
 
42
===================================================== HTTP Response End
 
43
`
 
44
)
 
45
 
 
46
// LoggingInspector implements request and response inspectors that log the full request and
 
47
// response to a supplied log.
 
48
type LoggingInspector struct {
 
49
        Logger *log.Logger
 
50
}
 
51
 
 
52
// WithInspection returns a PrepareDecorator that emits the http.Request to the supplied logger. The
 
53
// body is restored after being emitted.
 
54
//
 
55
// Note: Since it reads the entire Body, this decorator should not be used where body streaming is
 
56
// important. It is best used to trace JSON or similar body values.
 
57
func (li LoggingInspector) WithInspection() PrepareDecorator {
 
58
        return func(p Preparer) Preparer {
 
59
                return PreparerFunc(func(r *http.Request) (*http.Request, error) {
 
60
                        var body, b bytes.Buffer
 
61
 
 
62
                        defer r.Body.Close()
 
63
 
 
64
                        r.Body = ioutil.NopCloser(io.TeeReader(r.Body, &body))
 
65
                        r.Write(&b)
 
66
 
 
67
                        li.Logger.Printf(requestFormat, b.String())
 
68
 
 
69
                        r.Body = ioutil.NopCloser(&body)
 
70
                        return p.Prepare(r)
 
71
                })
 
72
        }
 
73
}
 
74
 
 
75
// ByInspecting returns a RespondDecorator that emits the http.Response to the supplied logger. The
 
76
// body is restored after being emitted.
 
77
//
 
78
// Note: Since it reads the entire Body, this decorator should not be used where body streaming is
 
79
// important. It is best used to trace JSON or similar body values.
 
80
func (li LoggingInspector) ByInspecting() RespondDecorator {
 
81
        return func(r Responder) Responder {
 
82
                return ResponderFunc(func(resp *http.Response) error {
 
83
                        var body, b bytes.Buffer
 
84
 
 
85
                        defer resp.Body.Close()
 
86
 
 
87
                        resp.Body = ioutil.NopCloser(io.TeeReader(resp.Body, &body))
 
88
                        resp.Write(&b)
 
89
 
 
90
                        li.Logger.Printf(responseFormat, b.String())
 
91
 
 
92
                        resp.Body = ioutil.NopCloser(&body)
 
93
                        return r.Respond(resp)
 
94
                })
 
95
        }
 
96
}
 
97
 
 
98
var (
 
99
        // DefaultClient is the base from which generated clients should create a Client instance. Users
 
100
        // can then established widely used Client defaults by replacing or modifying the DefaultClient
 
101
        // before instantiating a generated client.
 
102
        DefaultClient = Client{PollingMode: PollUntilDuration, PollingDuration: DefaultPollingDuration}
 
103
)
 
104
 
 
105
// Client is the base for autorest generated clients. It provides default, "do nothing"
 
106
// implementations of an Authorizer, RequestInspector, and ResponseInspector. It also returns the
 
107
// standard, undecorated http.Client as a default Sender. Lastly, it supports basic request polling,
 
108
// limited to a maximum number of attempts or a specified duration.
 
109
//
 
110
// Generated clients should also use Error (see NewError and NewErrorWithError) for errors and
 
111
// return responses that compose with Response.
 
112
//
 
113
// Most customization of generated clients is best achieved by supplying a custom Authorizer, custom
 
114
// RequestInspector, and / or custom ResponseInspector. Users may log requests, implement circuit
 
115
// breakers (see https://msdn.microsoft.com/en-us/library/dn589784.aspx) or otherwise influence
 
116
// sending the request by providing a decorated Sender.
 
117
type Client struct {
 
118
        Authorizer        Authorizer
 
119
        Sender            Sender
 
120
        RequestInspector  PrepareDecorator
 
121
        ResponseInspector RespondDecorator
 
122
 
 
123
        PollingMode     PollingMode
 
124
        PollingAttempts int
 
125
        PollingDuration time.Duration
 
126
 
 
127
        // UserAgent, if not empty, will be set as the HTTP User-Agent header on all requests sent
 
128
        // through the Do method.
 
129
        UserAgent string
 
130
}
 
131
 
 
132
// NewClientWithUserAgent returns an instance of the DefaultClient with the UserAgent set to the
 
133
// passed string.
 
134
func NewClientWithUserAgent(ua string) Client {
 
135
        c := DefaultClient
 
136
        c.UserAgent = ua
 
137
        return c
 
138
}
 
139
 
 
140
// IsPollingAllowed returns an error if the client allows polling and the passed http.Response
 
141
// requires it, otherwise it returns nil.
 
142
func (c Client) IsPollingAllowed(resp *http.Response, codes ...int) error {
 
143
        if c.DoNotPoll() && ResponseRequiresPolling(resp, codes...) {
 
144
                return NewError("autorest/Client", "IsPollingAllowed", "Response to %s requires polling but polling is disabled",
 
145
                        resp.Request.URL)
 
146
        }
 
147
        return nil
 
148
}
 
149
 
 
150
// PollAsNeeded is a convenience method that will poll if the passed http.Response requires it.
 
151
func (c Client) PollAsNeeded(resp *http.Response, codes ...int) (*http.Response, error) {
 
152
        if !ResponseRequiresPolling(resp, codes...) {
 
153
                return resp, nil
 
154
        }
 
155
 
 
156
        if c.DoNotPoll() {
 
157
                return resp, NewError("autorest/Client", "PollAsNeeded", "Polling for %s is required, but polling is disabled",
 
158
                        resp.Request.URL)
 
159
        }
 
160
 
 
161
        req, err := NewPollingRequest(resp, c)
 
162
        if err != nil {
 
163
                return resp, NewErrorWithError(err, "autorest/Client", "PollAsNeeded", "Unable to create polling request for response to %s",
 
164
                        resp.Request.URL)
 
165
        }
 
166
 
 
167
        Prepare(req,
 
168
                c.WithInspection())
 
169
 
 
170
        if c.PollForAttempts() {
 
171
                return PollForAttempts(c, req, DefaultPollingDelay, c.PollingAttempts, codes...)
 
172
        }
 
173
        return PollForDuration(c, req, DefaultPollingDelay, c.PollingDuration, codes...)
 
174
}
 
175
 
 
176
// DoNotPoll returns true if the client should not poll, false otherwise.
 
177
func (c Client) DoNotPoll() bool {
 
178
        return len(c.PollingMode) == 0 || c.PollingMode == DoNotPoll
 
179
}
 
180
 
 
181
// PollForAttempts returns true if the PollingMode is set to ForAttempts, false otherwise.
 
182
func (c Client) PollForAttempts() bool {
 
183
        return c.PollingMode == PollUntilAttempts
 
184
}
 
185
 
 
186
// PollForDuration return true if the PollingMode is set to ForDuration, false otherwise.
 
187
func (c Client) PollForDuration() bool {
 
188
        return c.PollingMode == PollUntilDuration
 
189
}
 
190
 
 
191
// Send sends the passed http.Request after applying authorization. It will poll if the client
 
192
// allows polling and the http.Response status code requires it. It will close the http.Response
 
193
// Body if the request returns an error.
 
194
func (c Client) Send(req *http.Request, codes ...int) (*http.Response, error) {
 
195
        if len(codes) == 0 {
 
196
                codes = []int{http.StatusOK}
 
197
        }
 
198
 
 
199
        req, err := Prepare(req,
 
200
                c.WithAuthorization(),
 
201
                c.WithInspection())
 
202
        if err != nil {
 
203
                return nil, NewErrorWithError(err, "autorest/Client", "Send", "Preparing request failed")
 
204
        }
 
205
 
 
206
        resp, err := SendWithSender(c, req,
 
207
                DoErrorUnlessStatusCode(codes...))
 
208
        if err == nil {
 
209
                err = c.IsPollingAllowed(resp)
 
210
                if err == nil {
 
211
                        resp, err = c.PollAsNeeded(resp)
 
212
                }
 
213
        }
 
214
 
 
215
        if err != nil {
 
216
                Respond(resp,
 
217
                        ByClosing())
 
218
        }
 
219
 
 
220
        return resp, err
 
221
}
 
222
 
 
223
// Do implements the Sender interface by invoking the active Sender. If Sender is not set, it uses
 
224
// a new instance of http.Client. In both cases it will, if UserAgent is set, apply set the
 
225
// User-Agent header.
 
226
func (c Client) Do(r *http.Request) (*http.Response, error) {
 
227
        if len(c.UserAgent) > 0 {
 
228
                r, _ = Prepare(r, WithUserAgent(c.UserAgent))
 
229
        }
 
230
        return c.sender().Do(r)
 
231
}
 
232
 
 
233
// sender returns the Sender to which to send requests.
 
234
func (c Client) sender() Sender {
 
235
        if c.Sender == nil {
 
236
                return &http.Client{}
 
237
        }
 
238
        return c.Sender
 
239
}
 
240
 
 
241
// WithAuthorization is a convenience method that returns the WithAuthorization PrepareDecorator
 
242
// from the current Authorizer. If not Authorizer is set, it uses the NullAuthorizer.
 
243
func (c Client) WithAuthorization() PrepareDecorator {
 
244
        return c.authorizer().WithAuthorization()
 
245
}
 
246
 
 
247
// authorizer returns the Authorizer to use.
 
248
func (c Client) authorizer() Authorizer {
 
249
        if c.Authorizer == nil {
 
250
                return NullAuthorizer{}
 
251
        }
 
252
        return c.Authorizer
 
253
}
 
254
 
 
255
// WithInspection is a convenience method that passes the request to the supplied RequestInspector,
 
256
// if present, or returns the WithNothing PrepareDecorator otherwise.
 
257
func (c Client) WithInspection() PrepareDecorator {
 
258
        if c.RequestInspector == nil {
 
259
                return WithNothing()
 
260
        }
 
261
        return c.RequestInspector
 
262
}
 
263
 
 
264
// ByInspecting is a convenience method that passes the response to the supplied ResponseInspector,
 
265
// if present, or returns the ByIgnoring RespondDecorator otherwise.
 
266
func (c Client) ByInspecting() RespondDecorator {
 
267
        if c.ResponseInspector == nil {
 
268
                return ByIgnoring()
 
269
        }
 
270
        return c.ResponseInspector
 
271
}
 
272
 
 
273
// Response serves as the base for all responses from generated clients. It provides access to the
 
274
// last http.Response.
 
275
type Response struct {
 
276
        *http.Response `json:"-"`
 
277
}
 
278
 
 
279
// GetPollingDelay extracts the polling delay from the Retry-After header of the response. If
 
280
// the header is absent or is malformed, it will return the supplied default delay time.Duration.
 
281
func (r Response) GetPollingDelay(defaultDelay time.Duration) time.Duration {
 
282
        return GetPollingDelay(r.Response, defaultDelay)
 
283
}
 
284
 
 
285
// GetPollingLocation retrieves the polling URL from the Location header of the response.
 
286
func (r Response) GetPollingLocation() string {
 
287
        return GetPollingLocation(r.Response)
 
288
}