2 Package autorest implements an HTTP request pipeline suitable for use across multiple go-routines
3 and provides the shared routines relied on by AutoRest (see https://github.com/Azure/autorest/)
6 The package breaks sending and responding to HTTP requests into three phases: Preparing, Sending,
7 and Responding. A typical pattern is:
9 req, err := Prepare(&http.Request{},
10 token.WithAuthorization())
12 resp, err := Send(req,
14 DoErrorIfStatusCode(http.StatusInternalServerError),
16 DoRetryForAttempts(5, time.Second))
22 Each phase relies on decorators to modify and / or manage processing. Decorators may first modify
23 and then pass the data along, pass the data first and then modify the result, or wrap themselves
24 around passing the data (such as a logger might do). Decorators run in the order provided. For
25 example, the following:
27 req, err := Prepare(&http.Request{},
28 WithBaseURL("https://microsoft.com/"),
35 https://microsoft.com/a/b/c
37 Preparers and Responders may be shared and re-used (assuming the underlying decorators support
38 sharing and re-use). Performant use is obtained by creating one or more Preparers and Responders
39 shared among multiple go-routines, and a single Sender shared among multiple sending go-routines,
40 all bound together by means of input / output channels.
42 Decorators hold their passed state within a closure (such as the path components in the example
43 above). Be careful to share Preparers and Responders only in a context where such held state
44 applies. For example, it may not make sense to share a Preparer that applies a query string from a
45 fixed set of values. Similarly, sharing a Responder that reads the response body into a passed
46 struct (e.g., ByUnmarshallingJson) is likely incorrect.
48 Lastly, the Swagger specification (https://swagger.io) that drives AutoRest
49 (https://github.com/Azure/autorest/) precisely defines two date forms: date and date-time. The
50 github.com/Azure/go-autorest/autorest/date package provides time.Time derivations to ensure
51 correct parsing and formatting.
53 Errors raised by autorest objects and methods will conform to the autorest.Error interface.
55 See the included examples for more detail. For details on the suggested use of this package by
56 generated clients, see the Client described below.
60 // Copyright 2017 Microsoft Corporation
62 // Licensed under the Apache License, Version 2.0 (the "License");
63 // you may not use this file except in compliance with the License.
64 // You may obtain a copy of the License at
66 // http://www.apache.org/licenses/LICENSE-2.0
68 // Unless required by applicable law or agreed to in writing, software
69 // distributed under the License is distributed on an "AS IS" BASIS,
70 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
71 // See the License for the specific language governing permissions and
72 // limitations under the License.
81 // HeaderLocation specifies the HTTP Location header.
82 HeaderLocation = "Location"
84 // HeaderRetryAfter specifies the HTTP Retry-After header.
85 HeaderRetryAfter = "Retry-After"
88 // ResponseHasStatusCode returns true if the status code in the HTTP Response is in the passed set
89 // and false otherwise.
90 func ResponseHasStatusCode(resp *http.Response, codes ...int) bool {
94 return containsInt(codes, resp.StatusCode)
97 // GetLocation retrieves the URL from the Location header of the passed response.
98 func GetLocation(resp *http.Response) string {
99 return resp.Header.Get(HeaderLocation)
102 // GetRetryAfter extracts the retry delay from the Retry-After header of the passed response. If
103 // the header is absent or is malformed, it will return the supplied default delay time.Duration.
104 func GetRetryAfter(resp *http.Response, defaultDelay time.Duration) time.Duration {
105 retry := resp.Header.Get(HeaderRetryAfter)
110 d, err := time.ParseDuration(retry + "s")
118 // NewPollingRequest allocates and returns a new http.Request to poll for the passed response.
119 func NewPollingRequest(resp *http.Response, cancel <-chan struct{}) (*http.Request, error) {
120 location := GetLocation(resp)
122 return nil, NewErrorWithResponse("autorest", "NewPollingRequest", resp, "Location header missing from response that requires polling")
125 req, err := Prepare(&http.Request{Cancel: cancel},
127 WithBaseURL(location))
129 return nil, NewErrorWithError(err, "autorest", "NewPollingRequest", nil, "Failure creating poll request to %s", location)
135 // NewPollingRequestWithContext allocates and returns a new http.Request with the specified context to poll for the passed response.
136 func NewPollingRequestWithContext(ctx context.Context, resp *http.Response) (*http.Request, error) {
137 location := GetLocation(resp)
139 return nil, NewErrorWithResponse("autorest", "NewPollingRequestWithContext", resp, "Location header missing from response that requires polling")
142 req, err := Prepare((&http.Request{}).WithContext(ctx),
144 WithBaseURL(location))
146 return nil, NewErrorWithError(err, "autorest", "NewPollingRequestWithContext", nil, "Failure creating poll request to %s", location)