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
17
// DefaultPollingDuration is the default total polling duration.
18
DefaultPollingDuration = 15 * time.Minute
21
// PollingMode sets how, if at all, clients composed with Client will poll.
22
type PollingMode string
25
// PollUntilAttempts polling mode polls until reaching a maximum number of attempts.
26
PollUntilAttempts PollingMode = "poll-until-attempts"
28
// PollUntilDuration polling mode polls until a specified time.Duration has passed.
29
PollUntilDuration PollingMode = "poll-until-duration"
31
// DoNotPoll disables polling.
32
DoNotPoll PollingMode = "not-at-all"
36
requestFormat = `HTTP Request Begin ===================================================
38
===================================================== HTTP Request End
40
responseFormat = `HTTP Response Begin ===================================================
42
===================================================== HTTP Response End
46
// LoggingInspector implements request and response inspectors that log the full request and
47
// response to a supplied log.
48
type LoggingInspector struct {
52
// WithInspection returns a PrepareDecorator that emits the http.Request to the supplied logger. The
53
// body is restored after being emitted.
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
64
r.Body = ioutil.NopCloser(io.TeeReader(r.Body, &body))
67
li.Logger.Printf(requestFormat, b.String())
69
r.Body = ioutil.NopCloser(&body)
75
// ByInspecting returns a RespondDecorator that emits the http.Response to the supplied logger. The
76
// body is restored after being emitted.
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
85
defer resp.Body.Close()
87
resp.Body = ioutil.NopCloser(io.TeeReader(resp.Body, &body))
90
li.Logger.Printf(responseFormat, b.String())
92
resp.Body = ioutil.NopCloser(&body)
93
return r.Respond(resp)
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}
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.
110
// Generated clients should also use Error (see NewError and NewErrorWithError) for errors and
111
// return responses that compose with Response.
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.
118
Authorizer Authorizer
120
RequestInspector PrepareDecorator
121
ResponseInspector RespondDecorator
123
PollingMode PollingMode
125
PollingDuration time.Duration
127
// UserAgent, if not empty, will be set as the HTTP User-Agent header on all requests sent
128
// through the Do method.
132
// NewClientWithUserAgent returns an instance of the DefaultClient with the UserAgent set to the
134
func NewClientWithUserAgent(ua string) Client {
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",
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...) {
157
return resp, NewError("autorest/Client", "PollAsNeeded", "Polling for %s is required, but polling is disabled",
161
req, err := NewPollingRequest(resp, c)
163
return resp, NewErrorWithError(err, "autorest/Client", "PollAsNeeded", "Unable to create polling request for response to %s",
170
if c.PollForAttempts() {
171
return PollForAttempts(c, req, DefaultPollingDelay, c.PollingAttempts, codes...)
173
return PollForDuration(c, req, DefaultPollingDelay, c.PollingDuration, codes...)
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
181
// PollForAttempts returns true if the PollingMode is set to ForAttempts, false otherwise.
182
func (c Client) PollForAttempts() bool {
183
return c.PollingMode == PollUntilAttempts
186
// PollForDuration return true if the PollingMode is set to ForDuration, false otherwise.
187
func (c Client) PollForDuration() bool {
188
return c.PollingMode == PollUntilDuration
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) {
196
codes = []int{http.StatusOK}
199
req, err := Prepare(req,
200
c.WithAuthorization(),
203
return nil, NewErrorWithError(err, "autorest/Client", "Send", "Preparing request failed")
206
resp, err := SendWithSender(c, req,
207
DoErrorUnlessStatusCode(codes...))
209
err = c.IsPollingAllowed(resp)
211
resp, err = c.PollAsNeeded(resp)
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))
230
return c.sender().Do(r)
233
// sender returns the Sender to which to send requests.
234
func (c Client) sender() Sender {
236
return &http.Client{}
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()
247
// authorizer returns the Authorizer to use.
248
func (c Client) authorizer() Authorizer {
249
if c.Authorizer == nil {
250
return NullAuthorizer{}
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 {
261
return c.RequestInspector
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 {
270
return c.ResponseInspector
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:"-"`
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)
285
// GetPollingLocation retrieves the polling URL from the Location header of the response.
286
func (r Response) GetPollingLocation() string {
287
return GetPollingLocation(r.Response)