Blame vendor/github.com/Azure/go-autorest/autorest/autorest.go

Packit 63bb0d
/*
Packit 63bb0d
Package autorest implements an HTTP request pipeline suitable for use across multiple go-routines
Packit 63bb0d
and provides the shared routines relied on by AutoRest (see https://github.com/Azure/autorest/)
Packit 63bb0d
generated Go code.
Packit 63bb0d
Packit 63bb0d
The package breaks sending and responding to HTTP requests into three phases: Preparing, Sending,
Packit 63bb0d
and Responding. A typical pattern is:
Packit 63bb0d
Packit 63bb0d
  req, err := Prepare(&http.Request{},
Packit 63bb0d
    token.WithAuthorization())
Packit 63bb0d
Packit 63bb0d
  resp, err := Send(req,
Packit 63bb0d
    WithLogging(logger),
Packit 63bb0d
    DoErrorIfStatusCode(http.StatusInternalServerError),
Packit 63bb0d
    DoCloseIfError(),
Packit 63bb0d
    DoRetryForAttempts(5, time.Second))
Packit 63bb0d
Packit 63bb0d
  err = Respond(resp,
Packit 63bb0d
    ByDiscardingBody(),
Packit 63bb0d
    ByClosing())
Packit 63bb0d
Packit 63bb0d
Each phase relies on decorators to modify and / or manage processing. Decorators may first modify
Packit 63bb0d
and then pass the data along, pass the data first and then modify the result, or wrap themselves
Packit 63bb0d
around passing the data (such as a logger might do). Decorators run in the order provided. For
Packit 63bb0d
example, the following:
Packit 63bb0d
Packit 63bb0d
  req, err := Prepare(&http.Request{},
Packit 63bb0d
    WithBaseURL("https://microsoft.com/"),
Packit 63bb0d
    WithPath("a"),
Packit 63bb0d
    WithPath("b"),
Packit 63bb0d
    WithPath("c"))
Packit 63bb0d
Packit 63bb0d
will set the URL to:
Packit 63bb0d
Packit 63bb0d
  https://microsoft.com/a/b/c
Packit 63bb0d
Packit 63bb0d
Preparers and Responders may be shared and re-used (assuming the underlying decorators support
Packit 63bb0d
sharing and re-use). Performant use is obtained by creating one or more Preparers and Responders
Packit 63bb0d
shared among multiple go-routines, and a single Sender shared among multiple sending go-routines,
Packit 63bb0d
all bound together by means of input / output channels.
Packit 63bb0d
Packit 63bb0d
Decorators hold their passed state within a closure (such as the path components in the example
Packit 63bb0d
above). Be careful to share Preparers and Responders only in a context where such held state
Packit 63bb0d
applies. For example, it may not make sense to share a Preparer that applies a query string from a
Packit 63bb0d
fixed set of values. Similarly, sharing a Responder that reads the response body into a passed
Packit 63bb0d
struct (e.g., ByUnmarshallingJson) is likely incorrect.
Packit 63bb0d
Packit 63bb0d
Lastly, the Swagger specification (https://swagger.io) that drives AutoRest
Packit 63bb0d
(https://github.com/Azure/autorest/) precisely defines two date forms: date and date-time. The
Packit 63bb0d
github.com/Azure/go-autorest/autorest/date package provides time.Time derivations to ensure
Packit 63bb0d
correct parsing and formatting.
Packit 63bb0d
Packit 63bb0d
Errors raised by autorest objects and methods will conform to the autorest.Error interface.
Packit 63bb0d
Packit 63bb0d
See the included examples for more detail. For details on the suggested use of this package by
Packit 63bb0d
generated clients, see the Client described below.
Packit 63bb0d
*/
Packit 63bb0d
package autorest
Packit 63bb0d
Packit 63bb0d
// Copyright 2017 Microsoft Corporation
Packit 63bb0d
//
Packit 63bb0d
//  Licensed under the Apache License, Version 2.0 (the "License");
Packit 63bb0d
//  you may not use this file except in compliance with the License.
Packit 63bb0d
//  You may obtain a copy of the License at
Packit 63bb0d
//
Packit 63bb0d
//      http://www.apache.org/licenses/LICENSE-2.0
Packit 63bb0d
//
Packit 63bb0d
//  Unless required by applicable law or agreed to in writing, software
Packit 63bb0d
//  distributed under the License is distributed on an "AS IS" BASIS,
Packit 63bb0d
//  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
Packit 63bb0d
//  See the License for the specific language governing permissions and
Packit 63bb0d
//  limitations under the License.
Packit 63bb0d
Packit 63bb0d
import (
Packit 63bb0d
	"context"
Packit 63bb0d
	"net/http"
Packit 63bb0d
	"time"
Packit 63bb0d
)
Packit 63bb0d
Packit 63bb0d
const (
Packit 63bb0d
	// HeaderLocation specifies the HTTP Location header.
Packit 63bb0d
	HeaderLocation = "Location"
Packit 63bb0d
Packit 63bb0d
	// HeaderRetryAfter specifies the HTTP Retry-After header.
Packit 63bb0d
	HeaderRetryAfter = "Retry-After"
Packit 63bb0d
)
Packit 63bb0d
Packit 63bb0d
// ResponseHasStatusCode returns true if the status code in the HTTP Response is in the passed set
Packit 63bb0d
// and false otherwise.
Packit 63bb0d
func ResponseHasStatusCode(resp *http.Response, codes ...int) bool {
Packit 63bb0d
	if resp == nil {
Packit 63bb0d
		return false
Packit 63bb0d
	}
Packit 63bb0d
	return containsInt(codes, resp.StatusCode)
Packit 63bb0d
}
Packit 63bb0d
Packit 63bb0d
// GetLocation retrieves the URL from the Location header of the passed response.
Packit 63bb0d
func GetLocation(resp *http.Response) string {
Packit 63bb0d
	return resp.Header.Get(HeaderLocation)
Packit 63bb0d
}
Packit 63bb0d
Packit 63bb0d
// GetRetryAfter extracts the retry delay from the Retry-After header of the passed response. If
Packit 63bb0d
// the header is absent or is malformed, it will return the supplied default delay time.Duration.
Packit 63bb0d
func GetRetryAfter(resp *http.Response, defaultDelay time.Duration) time.Duration {
Packit 63bb0d
	retry := resp.Header.Get(HeaderRetryAfter)
Packit 63bb0d
	if retry == "" {
Packit 63bb0d
		return defaultDelay
Packit 63bb0d
	}
Packit 63bb0d
Packit 63bb0d
	d, err := time.ParseDuration(retry + "s")
Packit 63bb0d
	if err != nil {
Packit 63bb0d
		return defaultDelay
Packit 63bb0d
	}
Packit 63bb0d
Packit 63bb0d
	return d
Packit 63bb0d
}
Packit 63bb0d
Packit 63bb0d
// NewPollingRequest allocates and returns a new http.Request to poll for the passed response.
Packit 63bb0d
func NewPollingRequest(resp *http.Response, cancel <-chan struct{}) (*http.Request, error) {
Packit 63bb0d
	location := GetLocation(resp)
Packit 63bb0d
	if location == "" {
Packit 63bb0d
		return nil, NewErrorWithResponse("autorest", "NewPollingRequest", resp, "Location header missing from response that requires polling")
Packit 63bb0d
	}
Packit 63bb0d
Packit 63bb0d
	req, err := Prepare(&http.Request{Cancel: cancel},
Packit 63bb0d
		AsGet(),
Packit 63bb0d
		WithBaseURL(location))
Packit 63bb0d
	if err != nil {
Packit 63bb0d
		return nil, NewErrorWithError(err, "autorest", "NewPollingRequest", nil, "Failure creating poll request to %s", location)
Packit 63bb0d
	}
Packit 63bb0d
Packit 63bb0d
	return req, nil
Packit 63bb0d
}
Packit 63bb0d
Packit 63bb0d
// NewPollingRequestWithContext allocates and returns a new http.Request with the specified context to poll for the passed response.
Packit 63bb0d
func NewPollingRequestWithContext(ctx context.Context, resp *http.Response) (*http.Request, error) {
Packit 63bb0d
	location := GetLocation(resp)
Packit 63bb0d
	if location == "" {
Packit 63bb0d
		return nil, NewErrorWithResponse("autorest", "NewPollingRequestWithContext", resp, "Location header missing from response that requires polling")
Packit 63bb0d
	}
Packit 63bb0d
Packit 63bb0d
	req, err := Prepare((&http.Request{}).WithContext(ctx),
Packit 63bb0d
		AsGet(),
Packit 63bb0d
		WithBaseURL(location))
Packit 63bb0d
	if err != nil {
Packit 63bb0d
		return nil, NewErrorWithError(err, "autorest", "NewPollingRequestWithContext", nil, "Failure creating poll request to %s", location)
Packit 63bb0d
	}
Packit 63bb0d
Packit 63bb0d
	return req, nil
Packit 63bb0d
}