sender.go 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458
  1. package autorest
  2. // Copyright 2017 Microsoft Corporation
  3. //
  4. // Licensed under the Apache License, Version 2.0 (the "License");
  5. // you may not use this file except in compliance with the License.
  6. // You may obtain a copy of the License at
  7. //
  8. // http://www.apache.org/licenses/LICENSE-2.0
  9. //
  10. // Unless required by applicable law or agreed to in writing, software
  11. // distributed under the License is distributed on an "AS IS" BASIS,
  12. // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  13. // See the License for the specific language governing permissions and
  14. // limitations under the License.
  15. import (
  16. "context"
  17. "crypto/tls"
  18. "fmt"
  19. "log"
  20. "math"
  21. "net"
  22. "net/http"
  23. "net/http/cookiejar"
  24. "strconv"
  25. "sync"
  26. "time"
  27. "github.com/Azure/go-autorest/logger"
  28. "github.com/Azure/go-autorest/tracing"
  29. )
  30. // there is one sender per TLS renegotiation type, i.e. count of tls.RenegotiationSupport enums
  31. const defaultSendersCount = 3
  32. type defaultSender struct {
  33. sender Sender
  34. init *sync.Once
  35. }
  36. // each type of sender will be created on demand in sender()
  37. var defaultSenders [defaultSendersCount]defaultSender
  38. func init() {
  39. for i := 0; i < defaultSendersCount; i++ {
  40. defaultSenders[i].init = &sync.Once{}
  41. }
  42. }
  43. // used as a key type in context.WithValue()
  44. type ctxSendDecorators struct{}
  45. // WithSendDecorators adds the specified SendDecorators to the provided context.
  46. // If no SendDecorators are provided the context is unchanged.
  47. func WithSendDecorators(ctx context.Context, sendDecorator []SendDecorator) context.Context {
  48. if len(sendDecorator) == 0 {
  49. return ctx
  50. }
  51. return context.WithValue(ctx, ctxSendDecorators{}, sendDecorator)
  52. }
  53. // GetSendDecorators returns the SendDecorators in the provided context or the provided default SendDecorators.
  54. func GetSendDecorators(ctx context.Context, defaultSendDecorators ...SendDecorator) []SendDecorator {
  55. inCtx := ctx.Value(ctxSendDecorators{})
  56. if sd, ok := inCtx.([]SendDecorator); ok {
  57. return sd
  58. }
  59. return defaultSendDecorators
  60. }
  61. // Sender is the interface that wraps the Do method to send HTTP requests.
  62. //
  63. // The standard http.Client conforms to this interface.
  64. type Sender interface {
  65. Do(*http.Request) (*http.Response, error)
  66. }
  67. // SenderFunc is a method that implements the Sender interface.
  68. type SenderFunc func(*http.Request) (*http.Response, error)
  69. // Do implements the Sender interface on SenderFunc.
  70. func (sf SenderFunc) Do(r *http.Request) (*http.Response, error) {
  71. return sf(r)
  72. }
  73. // SendDecorator takes and possibly decorates, by wrapping, a Sender. Decorators may affect the
  74. // http.Request and pass it along or, first, pass the http.Request along then react to the
  75. // http.Response result.
  76. type SendDecorator func(Sender) Sender
  77. // CreateSender creates, decorates, and returns, as a Sender, the default http.Client.
  78. func CreateSender(decorators ...SendDecorator) Sender {
  79. return DecorateSender(sender(tls.RenegotiateNever), decorators...)
  80. }
  81. // DecorateSender accepts a Sender and a, possibly empty, set of SendDecorators, which is applies to
  82. // the Sender. Decorators are applied in the order received, but their affect upon the request
  83. // depends on whether they are a pre-decorator (change the http.Request and then pass it along) or a
  84. // post-decorator (pass the http.Request along and react to the results in http.Response).
  85. func DecorateSender(s Sender, decorators ...SendDecorator) Sender {
  86. for _, decorate := range decorators {
  87. s = decorate(s)
  88. }
  89. return s
  90. }
  91. // Send sends, by means of the default http.Client, the passed http.Request, returning the
  92. // http.Response and possible error. It also accepts a, possibly empty, set of SendDecorators which
  93. // it will apply the http.Client before invoking the Do method.
  94. //
  95. // Send is a convenience method and not recommended for production. Advanced users should use
  96. // SendWithSender, passing and sharing their own Sender (e.g., instance of http.Client).
  97. //
  98. // Send will not poll or retry requests.
  99. func Send(r *http.Request, decorators ...SendDecorator) (*http.Response, error) {
  100. return SendWithSender(sender(tls.RenegotiateNever), r, decorators...)
  101. }
  102. // SendWithSender sends the passed http.Request, through the provided Sender, returning the
  103. // http.Response and possible error. It also accepts a, possibly empty, set of SendDecorators which
  104. // it will apply the http.Client before invoking the Do method.
  105. //
  106. // SendWithSender will not poll or retry requests.
  107. func SendWithSender(s Sender, r *http.Request, decorators ...SendDecorator) (*http.Response, error) {
  108. return DecorateSender(s, decorators...).Do(r)
  109. }
  110. func sender(renengotiation tls.RenegotiationSupport) Sender {
  111. // note that we can't init defaultSenders in init() since it will
  112. // execute before calling code has had a chance to enable tracing
  113. defaultSenders[renengotiation].init.Do(func() {
  114. // copied from http.DefaultTransport with a TLS minimum version.
  115. transport := &http.Transport{
  116. Proxy: http.ProxyFromEnvironment,
  117. DialContext: (&net.Dialer{
  118. Timeout: 30 * time.Second,
  119. KeepAlive: 30 * time.Second,
  120. }).DialContext,
  121. ForceAttemptHTTP2: true,
  122. MaxIdleConns: 100,
  123. IdleConnTimeout: 90 * time.Second,
  124. TLSHandshakeTimeout: 10 * time.Second,
  125. ExpectContinueTimeout: 1 * time.Second,
  126. TLSClientConfig: &tls.Config{
  127. MinVersion: tls.VersionTLS12,
  128. Renegotiation: renengotiation,
  129. },
  130. }
  131. var roundTripper http.RoundTripper = transport
  132. if tracing.IsEnabled() {
  133. roundTripper = tracing.NewTransport(transport)
  134. }
  135. j, _ := cookiejar.New(nil)
  136. defaultSenders[renengotiation].sender = &http.Client{Jar: j, Transport: roundTripper}
  137. })
  138. return defaultSenders[renengotiation].sender
  139. }
  140. // AfterDelay returns a SendDecorator that delays for the passed time.Duration before
  141. // invoking the Sender. The delay may be terminated by closing the optional channel on the
  142. // http.Request. If canceled, no further Senders are invoked.
  143. func AfterDelay(d time.Duration) SendDecorator {
  144. return func(s Sender) Sender {
  145. return SenderFunc(func(r *http.Request) (*http.Response, error) {
  146. if !DelayForBackoff(d, 0, r.Context().Done()) {
  147. return nil, fmt.Errorf("autorest: AfterDelay canceled before full delay")
  148. }
  149. return s.Do(r)
  150. })
  151. }
  152. }
  153. // AsIs returns a SendDecorator that invokes the passed Sender without modifying the http.Request.
  154. func AsIs() SendDecorator {
  155. return func(s Sender) Sender {
  156. return SenderFunc(func(r *http.Request) (*http.Response, error) {
  157. return s.Do(r)
  158. })
  159. }
  160. }
  161. // DoCloseIfError returns a SendDecorator that first invokes the passed Sender after which
  162. // it closes the response if the passed Sender returns an error and the response body exists.
  163. func DoCloseIfError() SendDecorator {
  164. return func(s Sender) Sender {
  165. return SenderFunc(func(r *http.Request) (*http.Response, error) {
  166. resp, err := s.Do(r)
  167. if err != nil {
  168. Respond(resp, ByDiscardingBody(), ByClosing())
  169. }
  170. return resp, err
  171. })
  172. }
  173. }
  174. // DoErrorIfStatusCode returns a SendDecorator that emits an error if the response StatusCode is
  175. // among the set passed. Since these are artificial errors, the response body may still require
  176. // closing.
  177. func DoErrorIfStatusCode(codes ...int) SendDecorator {
  178. return func(s Sender) Sender {
  179. return SenderFunc(func(r *http.Request) (*http.Response, error) {
  180. resp, err := s.Do(r)
  181. if err == nil && ResponseHasStatusCode(resp, codes...) {
  182. err = NewErrorWithResponse("autorest", "DoErrorIfStatusCode", resp, "%v %v failed with %s",
  183. resp.Request.Method,
  184. resp.Request.URL,
  185. resp.Status)
  186. }
  187. return resp, err
  188. })
  189. }
  190. }
  191. // DoErrorUnlessStatusCode returns a SendDecorator that emits an error unless the response
  192. // StatusCode is among the set passed. Since these are artificial errors, the response body
  193. // may still require closing.
  194. func DoErrorUnlessStatusCode(codes ...int) SendDecorator {
  195. return func(s Sender) Sender {
  196. return SenderFunc(func(r *http.Request) (*http.Response, error) {
  197. resp, err := s.Do(r)
  198. if err == nil && !ResponseHasStatusCode(resp, codes...) {
  199. err = NewErrorWithResponse("autorest", "DoErrorUnlessStatusCode", resp, "%v %v failed with %s",
  200. resp.Request.Method,
  201. resp.Request.URL,
  202. resp.Status)
  203. }
  204. return resp, err
  205. })
  206. }
  207. }
  208. // DoPollForStatusCodes returns a SendDecorator that polls if the http.Response contains one of the
  209. // passed status codes. It expects the http.Response to contain a Location header providing the
  210. // URL at which to poll (using GET) and will poll until the time passed is equal to or greater than
  211. // the supplied duration. It will delay between requests for the duration specified in the
  212. // RetryAfter header or, if the header is absent, the passed delay. Polling may be canceled by
  213. // closing the optional channel on the http.Request.
  214. func DoPollForStatusCodes(duration time.Duration, delay time.Duration, codes ...int) SendDecorator {
  215. return func(s Sender) Sender {
  216. return SenderFunc(func(r *http.Request) (resp *http.Response, err error) {
  217. resp, err = s.Do(r)
  218. if err == nil && ResponseHasStatusCode(resp, codes...) {
  219. r, err = NewPollingRequestWithContext(r.Context(), resp)
  220. for err == nil && ResponseHasStatusCode(resp, codes...) {
  221. Respond(resp,
  222. ByDiscardingBody(),
  223. ByClosing())
  224. resp, err = SendWithSender(s, r,
  225. AfterDelay(GetRetryAfter(resp, delay)))
  226. }
  227. }
  228. return resp, err
  229. })
  230. }
  231. }
  232. // DoRetryForAttempts returns a SendDecorator that retries a failed request for up to the specified
  233. // number of attempts, exponentially backing off between requests using the supplied backoff
  234. // time.Duration (which may be zero). Retrying may be canceled by closing the optional channel on
  235. // the http.Request.
  236. func DoRetryForAttempts(attempts int, backoff time.Duration) SendDecorator {
  237. return func(s Sender) Sender {
  238. return SenderFunc(func(r *http.Request) (resp *http.Response, err error) {
  239. rr := NewRetriableRequest(r)
  240. for attempt := 0; attempt < attempts; attempt++ {
  241. err = rr.Prepare()
  242. if err != nil {
  243. return resp, err
  244. }
  245. DrainResponseBody(resp)
  246. resp, err = s.Do(rr.Request())
  247. if err == nil {
  248. return resp, err
  249. }
  250. logger.Instance.Writef(logger.LogError, "DoRetryForAttempts: received error for attempt %d: %v\n", attempt+1, err)
  251. if !DelayForBackoff(backoff, attempt, r.Context().Done()) {
  252. return nil, r.Context().Err()
  253. }
  254. }
  255. return resp, err
  256. })
  257. }
  258. }
  259. // Count429AsRetry indicates that a 429 response should be included as a retry attempt.
  260. var Count429AsRetry = true
  261. // Max429Delay is the maximum duration to wait between retries on a 429 if no Retry-After header was received.
  262. var Max429Delay time.Duration
  263. // DoRetryForStatusCodes returns a SendDecorator that retries for specified statusCodes for up to the specified
  264. // number of attempts, exponentially backing off between requests using the supplied backoff
  265. // time.Duration (which may be zero). Retrying may be canceled by cancelling the context on the http.Request.
  266. // NOTE: Code http.StatusTooManyRequests (429) will *not* be counted against the number of attempts.
  267. func DoRetryForStatusCodes(attempts int, backoff time.Duration, codes ...int) SendDecorator {
  268. return func(s Sender) Sender {
  269. return SenderFunc(func(r *http.Request) (*http.Response, error) {
  270. return doRetryForStatusCodesImpl(s, r, Count429AsRetry, attempts, backoff, 0, codes...)
  271. })
  272. }
  273. }
  274. // DoRetryForStatusCodesWithCap returns a SendDecorator that retries for specified statusCodes for up to the
  275. // specified number of attempts, exponentially backing off between requests using the supplied backoff
  276. // time.Duration (which may be zero). To cap the maximum possible delay between iterations specify a value greater
  277. // than zero for cap. Retrying may be canceled by cancelling the context on the http.Request.
  278. func DoRetryForStatusCodesWithCap(attempts int, backoff, cap time.Duration, codes ...int) SendDecorator {
  279. return func(s Sender) Sender {
  280. return SenderFunc(func(r *http.Request) (*http.Response, error) {
  281. return doRetryForStatusCodesImpl(s, r, Count429AsRetry, attempts, backoff, cap, codes...)
  282. })
  283. }
  284. }
  285. func doRetryForStatusCodesImpl(s Sender, r *http.Request, count429 bool, attempts int, backoff, cap time.Duration, codes ...int) (resp *http.Response, err error) {
  286. rr := NewRetriableRequest(r)
  287. // Increment to add the first call (attempts denotes number of retries)
  288. for attempt, delayCount := 0, 0; attempt < attempts+1; {
  289. err = rr.Prepare()
  290. if err != nil {
  291. return
  292. }
  293. DrainResponseBody(resp)
  294. resp, err = s.Do(rr.Request())
  295. // we want to retry if err is not nil (e.g. transient network failure). note that for failed authentication
  296. // resp and err will both have a value, so in this case we don't want to retry as it will never succeed.
  297. if err == nil && !ResponseHasStatusCode(resp, codes...) || IsTokenRefreshError(err) {
  298. return resp, err
  299. }
  300. if err != nil {
  301. logger.Instance.Writef(logger.LogError, "DoRetryForStatusCodes: received error for attempt %d: %v\n", attempt+1, err)
  302. }
  303. delayed := DelayWithRetryAfter(resp, r.Context().Done())
  304. // if this was a 429 set the delay cap as specified.
  305. // applicable only in the absence of a retry-after header.
  306. if resp != nil && resp.StatusCode == http.StatusTooManyRequests {
  307. cap = Max429Delay
  308. }
  309. if !delayed && !DelayForBackoffWithCap(backoff, cap, delayCount, r.Context().Done()) {
  310. return resp, r.Context().Err()
  311. }
  312. // when count429 == false don't count a 429 against the number
  313. // of attempts so that we continue to retry until it succeeds
  314. if count429 || (resp == nil || resp.StatusCode != http.StatusTooManyRequests) {
  315. attempt++
  316. }
  317. // delay count is tracked separately from attempts to
  318. // ensure that 429 participates in exponential back-off
  319. delayCount++
  320. }
  321. return resp, err
  322. }
  323. // DelayWithRetryAfter invokes time.After for the duration specified in the "Retry-After" header.
  324. // The value of Retry-After can be either the number of seconds or a date in RFC1123 format.
  325. // The function returns true after successfully waiting for the specified duration. If there is
  326. // no Retry-After header or the wait is cancelled the return value is false.
  327. func DelayWithRetryAfter(resp *http.Response, cancel <-chan struct{}) bool {
  328. if resp == nil {
  329. return false
  330. }
  331. var dur time.Duration
  332. ra := resp.Header.Get("Retry-After")
  333. if retryAfter, _ := strconv.Atoi(ra); retryAfter > 0 {
  334. dur = time.Duration(retryAfter) * time.Second
  335. } else if t, err := time.Parse(time.RFC1123, ra); err == nil {
  336. dur = t.Sub(time.Now())
  337. }
  338. if dur > 0 {
  339. select {
  340. case <-time.After(dur):
  341. return true
  342. case <-cancel:
  343. return false
  344. }
  345. }
  346. return false
  347. }
  348. // DoRetryForDuration returns a SendDecorator that retries the request until the total time is equal
  349. // to or greater than the specified duration, exponentially backing off between requests using the
  350. // supplied backoff time.Duration (which may be zero). Retrying may be canceled by closing the
  351. // optional channel on the http.Request.
  352. func DoRetryForDuration(d time.Duration, backoff time.Duration) SendDecorator {
  353. return func(s Sender) Sender {
  354. return SenderFunc(func(r *http.Request) (resp *http.Response, err error) {
  355. rr := NewRetriableRequest(r)
  356. end := time.Now().Add(d)
  357. for attempt := 0; time.Now().Before(end); attempt++ {
  358. err = rr.Prepare()
  359. if err != nil {
  360. return resp, err
  361. }
  362. DrainResponseBody(resp)
  363. resp, err = s.Do(rr.Request())
  364. if err == nil {
  365. return resp, err
  366. }
  367. logger.Instance.Writef(logger.LogError, "DoRetryForDuration: received error for attempt %d: %v\n", attempt+1, err)
  368. if !DelayForBackoff(backoff, attempt, r.Context().Done()) {
  369. return nil, r.Context().Err()
  370. }
  371. }
  372. return resp, err
  373. })
  374. }
  375. }
  376. // WithLogging returns a SendDecorator that implements simple before and after logging of the
  377. // request.
  378. func WithLogging(logger *log.Logger) SendDecorator {
  379. return func(s Sender) Sender {
  380. return SenderFunc(func(r *http.Request) (*http.Response, error) {
  381. logger.Printf("Sending %s %s", r.Method, r.URL)
  382. resp, err := s.Do(r)
  383. if err != nil {
  384. logger.Printf("%s %s received error '%v'", r.Method, r.URL, err)
  385. } else {
  386. logger.Printf("%s %s received %s", r.Method, r.URL, resp.Status)
  387. }
  388. return resp, err
  389. })
  390. }
  391. }
  392. // DelayForBackoff invokes time.After for the supplied backoff duration raised to the power of
  393. // passed attempt (i.e., an exponential backoff delay). Backoff duration is in seconds and can set
  394. // to zero for no delay. The delay may be canceled by closing the passed channel. If terminated early,
  395. // returns false.
  396. // Note: Passing attempt 1 will result in doubling "backoff" duration. Treat this as a zero-based attempt
  397. // count.
  398. func DelayForBackoff(backoff time.Duration, attempt int, cancel <-chan struct{}) bool {
  399. return DelayForBackoffWithCap(backoff, 0, attempt, cancel)
  400. }
  401. // DelayForBackoffWithCap invokes time.After for the supplied backoff duration raised to the power of
  402. // passed attempt (i.e., an exponential backoff delay). Backoff duration is in seconds and can set
  403. // to zero for no delay. To cap the maximum possible delay specify a value greater than zero for cap.
  404. // The delay may be canceled by closing the passed channel. If terminated early, returns false.
  405. // Note: Passing attempt 1 will result in doubling "backoff" duration. Treat this as a zero-based attempt
  406. // count.
  407. func DelayForBackoffWithCap(backoff, cap time.Duration, attempt int, cancel <-chan struct{}) bool {
  408. d := time.Duration(backoff.Seconds()*math.Pow(2, float64(attempt))) * time.Second
  409. if cap > 0 && d > cap {
  410. d = cap
  411. }
  412. logger.Instance.Writef(logger.LogInfo, "DelayForBackoffWithCap: sleeping for %s\n", d)
  413. select {
  414. case <-time.After(d):
  415. return true
  416. case <-cancel:
  417. return false
  418. }
  419. }