Code refactoring for bpa operator
[icn.git] / cmd / bpa-operator / vendor / github.com / Azure / go-autorest / autorest / client.go
1 package autorest
2
3 // Copyright 2017 Microsoft Corporation
4 //
5 //  Licensed under the Apache License, Version 2.0 (the "License");
6 //  you may not use this file except in compliance with the License.
7 //  You may obtain a copy of the License at
8 //
9 //      http://www.apache.org/licenses/LICENSE-2.0
10 //
11 //  Unless required by applicable law or agreed to in writing, software
12 //  distributed under the License is distributed on an "AS IS" BASIS,
13 //  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 //  See the License for the specific language governing permissions and
15 //  limitations under the License.
16
17 import (
18         "bytes"
19         "crypto/tls"
20         "fmt"
21         "io"
22         "io/ioutil"
23         "log"
24         "net/http"
25         "net/http/cookiejar"
26         "strings"
27         "time"
28
29         "github.com/Azure/go-autorest/logger"
30         "github.com/Azure/go-autorest/tracing"
31 )
32
33 const (
34         // DefaultPollingDelay is a reasonable delay between polling requests.
35         DefaultPollingDelay = 60 * time.Second
36
37         // DefaultPollingDuration is a reasonable total polling duration.
38         DefaultPollingDuration = 15 * time.Minute
39
40         // DefaultRetryAttempts is number of attempts for retry status codes (5xx).
41         DefaultRetryAttempts = 3
42
43         // DefaultRetryDuration is the duration to wait between retries.
44         DefaultRetryDuration = 30 * time.Second
45 )
46
47 var (
48         // StatusCodesForRetry are a defined group of status code for which the client will retry
49         StatusCodesForRetry = []int{
50                 http.StatusRequestTimeout,      // 408
51                 http.StatusTooManyRequests,     // 429
52                 http.StatusInternalServerError, // 500
53                 http.StatusBadGateway,          // 502
54                 http.StatusServiceUnavailable,  // 503
55                 http.StatusGatewayTimeout,      // 504
56         }
57 )
58
59 const (
60         requestFormat = `HTTP Request Begin ===================================================
61 %s
62 ===================================================== HTTP Request End
63 `
64         responseFormat = `HTTP Response Begin ===================================================
65 %s
66 ===================================================== HTTP Response End
67 `
68 )
69
70 // Response serves as the base for all responses from generated clients. It provides access to the
71 // last http.Response.
72 type Response struct {
73         *http.Response `json:"-"`
74 }
75
76 // LoggingInspector implements request and response inspectors that log the full request and
77 // response to a supplied log.
78 type LoggingInspector struct {
79         Logger *log.Logger
80 }
81
82 // WithInspection returns a PrepareDecorator that emits the http.Request to the supplied logger. The
83 // body is restored after being emitted.
84 //
85 // Note: Since it reads the entire Body, this decorator should not be used where body streaming is
86 // important. It is best used to trace JSON or similar body values.
87 func (li LoggingInspector) WithInspection() PrepareDecorator {
88         return func(p Preparer) Preparer {
89                 return PreparerFunc(func(r *http.Request) (*http.Request, error) {
90                         var body, b bytes.Buffer
91
92                         defer r.Body.Close()
93
94                         r.Body = ioutil.NopCloser(io.TeeReader(r.Body, &body))
95                         if err := r.Write(&b); err != nil {
96                                 return nil, fmt.Errorf("Failed to write response: %v", err)
97                         }
98
99                         li.Logger.Printf(requestFormat, b.String())
100
101                         r.Body = ioutil.NopCloser(&body)
102                         return p.Prepare(r)
103                 })
104         }
105 }
106
107 // ByInspecting returns a RespondDecorator that emits the http.Response to the supplied logger. The
108 // body is restored after being emitted.
109 //
110 // Note: Since it reads the entire Body, this decorator should not be used where body streaming is
111 // important. It is best used to trace JSON or similar body values.
112 func (li LoggingInspector) ByInspecting() RespondDecorator {
113         return func(r Responder) Responder {
114                 return ResponderFunc(func(resp *http.Response) error {
115                         var body, b bytes.Buffer
116                         defer resp.Body.Close()
117                         resp.Body = ioutil.NopCloser(io.TeeReader(resp.Body, &body))
118                         if err := resp.Write(&b); err != nil {
119                                 return fmt.Errorf("Failed to write response: %v", err)
120                         }
121
122                         li.Logger.Printf(responseFormat, b.String())
123
124                         resp.Body = ioutil.NopCloser(&body)
125                         return r.Respond(resp)
126                 })
127         }
128 }
129
130 // Client is the base for autorest generated clients. It provides default, "do nothing"
131 // implementations of an Authorizer, RequestInspector, and ResponseInspector. It also returns the
132 // standard, undecorated http.Client as a default Sender.
133 //
134 // Generated clients should also use Error (see NewError and NewErrorWithError) for errors and
135 // return responses that compose with Response.
136 //
137 // Most customization of generated clients is best achieved by supplying a custom Authorizer, custom
138 // RequestInspector, and / or custom ResponseInspector. Users may log requests, implement circuit
139 // breakers (see https://msdn.microsoft.com/en-us/library/dn589784.aspx) or otherwise influence
140 // sending the request by providing a decorated Sender.
141 type Client struct {
142         Authorizer        Authorizer
143         Sender            Sender
144         RequestInspector  PrepareDecorator
145         ResponseInspector RespondDecorator
146
147         // PollingDelay sets the polling frequency used in absence of a Retry-After HTTP header
148         PollingDelay time.Duration
149
150         // PollingDuration sets the maximum polling time after which an error is returned.
151         // Setting this to zero will use the provided context to control the duration.
152         PollingDuration time.Duration
153
154         // RetryAttempts sets the default number of retry attempts for client.
155         RetryAttempts int
156
157         // RetryDuration sets the delay duration for retries.
158         RetryDuration time.Duration
159
160         // UserAgent, if not empty, will be set as the HTTP User-Agent header on all requests sent
161         // through the Do method.
162         UserAgent string
163
164         Jar http.CookieJar
165
166         // Set to true to skip attempted registration of resource providers (false by default).
167         SkipResourceProviderRegistration bool
168 }
169
170 // NewClientWithUserAgent returns an instance of a Client with the UserAgent set to the passed
171 // string.
172 func NewClientWithUserAgent(ua string) Client {
173         c := Client{
174                 PollingDelay:    DefaultPollingDelay,
175                 PollingDuration: DefaultPollingDuration,
176                 RetryAttempts:   DefaultRetryAttempts,
177                 RetryDuration:   DefaultRetryDuration,
178                 UserAgent:       UserAgent(),
179         }
180         c.Sender = c.sender()
181         c.AddToUserAgent(ua)
182         return c
183 }
184
185 // AddToUserAgent adds an extension to the current user agent
186 func (c *Client) AddToUserAgent(extension string) error {
187         if extension != "" {
188                 c.UserAgent = fmt.Sprintf("%s %s", c.UserAgent, extension)
189                 return nil
190         }
191         return fmt.Errorf("Extension was empty, User Agent stayed as %s", c.UserAgent)
192 }
193
194 // Do implements the Sender interface by invoking the active Sender after applying authorization.
195 // If Sender is not set, it uses a new instance of http.Client. In both cases it will, if UserAgent
196 // is set, apply set the User-Agent header.
197 func (c Client) Do(r *http.Request) (*http.Response, error) {
198         if r.UserAgent() == "" {
199                 r, _ = Prepare(r,
200                         WithUserAgent(c.UserAgent))
201         }
202         // NOTE: c.WithInspection() must be last in the list so that it can inspect all preceding operations
203         r, err := Prepare(r,
204                 c.WithAuthorization(),
205                 c.WithInspection())
206         if err != nil {
207                 var resp *http.Response
208                 if detErr, ok := err.(DetailedError); ok {
209                         // if the authorization failed (e.g. invalid credentials) there will
210                         // be a response associated with the error, be sure to return it.
211                         resp = detErr.Response
212                 }
213                 return resp, NewErrorWithError(err, "autorest/Client", "Do", nil, "Preparing request failed")
214         }
215         logger.Instance.WriteRequest(r, logger.Filter{
216                 Header: func(k string, v []string) (bool, []string) {
217                         // remove the auth token from the log
218                         if strings.EqualFold(k, "Authorization") || strings.EqualFold(k, "Ocp-Apim-Subscription-Key") {
219                                 v = []string{"**REDACTED**"}
220                         }
221                         return true, v
222                 },
223         })
224         resp, err := SendWithSender(c.sender(), r)
225         logger.Instance.WriteResponse(resp, logger.Filter{})
226         Respond(resp, c.ByInspecting())
227         return resp, err
228 }
229
230 // sender returns the Sender to which to send requests.
231 func (c Client) sender() Sender {
232         if c.Sender == nil {
233                 j, _ := cookiejar.New(nil)
234                 tracing.Transport.Base = &http.Transport{
235                         TLSClientConfig: &tls.Config{
236                                 MinVersion: tls.VersionTLS12,
237                         },
238                 }
239                 client := &http.Client{Jar: j, Transport: tracing.Transport}
240                 return client
241         }
242
243         return c.Sender
244 }
245
246 // WithAuthorization is a convenience method that returns the WithAuthorization PrepareDecorator
247 // from the current Authorizer. If not Authorizer is set, it uses the NullAuthorizer.
248 func (c Client) WithAuthorization() PrepareDecorator {
249         return c.authorizer().WithAuthorization()
250 }
251
252 // authorizer returns the Authorizer to use.
253 func (c Client) authorizer() Authorizer {
254         if c.Authorizer == nil {
255                 return NullAuthorizer{}
256         }
257         return c.Authorizer
258 }
259
260 // WithInspection is a convenience method that passes the request to the supplied RequestInspector,
261 // if present, or returns the WithNothing PrepareDecorator otherwise.
262 func (c Client) WithInspection() PrepareDecorator {
263         if c.RequestInspector == nil {
264                 return WithNothing()
265         }
266         return c.RequestInspector
267 }
268
269 // ByInspecting is a convenience method that passes the response to the supplied ResponseInspector,
270 // if present, or returns the ByIgnoring RespondDecorator otherwise.
271 func (c Client) ByInspecting() RespondDecorator {
272         if c.ResponseInspector == nil {
273                 return ByIgnoring()
274         }
275         return c.ResponseInspector
276 }