retriable

package
v0.25.559 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Mar 8, 2024 License: MIT Imports: 36 Imported by: 3

README

retriable

Rich HTTP client

Generic HTTP features

The package provides generic interface to send HTTP requests, and decode responses.

// GenericHTTP defines a number of generalized HTTP request handling wrappers
type GenericHTTP interface {
	// Request sends request to the specified hosts.
	// The supplied hosts are tried in order until one succeeds.
	// It will decode the response payload into the supplied body parameter.
	// It returns the HTTP headers, status code, and an optional error.
	// For responses with status codes >= 300 it will try and convert the response
	// into a Go error.
	// If configured, this call will apply retry logic.
	//
	// host should include all the protocol/host/port preamble, e.g. https://foo.bar:3444
	// path should be an absolute URI path, i.e. /foo/bar/baz
	// requestBody can be io.Reader, []byte, or an object to be JSON encoded
	// responseBody can be io.Writer, or a struct to decode JSON into.
	Request(ctx context.Context, method string, host string, path string, requestBody interface{}, responseBody interface{}) (http.Header, int, error)

	// RequestURL is similar to Request but uses raw URL to one host
	RequestURL(ctx context.Context, method, rawURL string, requestBody interface{}, responseBody interface{}) (http.Header, int, error)

	// HeadTo makes HEAD request against the specified hosts.
	// The supplied hosts are tried in order until one succeeds.
	//
	// host should include all the protocol/host/port preamble, e.g. https://foo.bar:3444
	// path should be an absolute URI path, i.e. /foo/bar/baz
	HeadTo(ctx context.Context, host string, path string) (http.Header, int, error)
}

Documentation

Index

Constants

View Source
const (
	// Success returned when request succeeded
	Success = "success"
	// NotFound returned when request returned 404
	NotFound = "not-found"
	// LimitExceeded returned when retry limit exceeded
	LimitExceeded = "limit-exceeded"
	// DeadlineExceeded returned when request was timed out
	DeadlineExceeded = "deadline"
	// Cancelled returned when request was cancelled
	Cancelled = "cancelled"
	// NonRetriableError returned when non-retriable error occured
	NonRetriableError = "non-retriable"
)
View Source
const (
	// DefaultReplayNonceHeader provides header name for nonce
	DefaultReplayNonceHeader = "Replay-Nonce"
)

Variables

View Source
var DefaultNonRetriableErrors = []string{
	"no such host",
	"TLS handshake error",
	"certificate signed by unknown authority",
	"client didn't provide a certificate",
	"tls: bad certificate",
	"x509: certificate",
	"x509: cannot validate certificate",
	"server gave HTTP response to HTTPS client",
	"dial tcp: lookup",
	"peer reset",
}

DefaultNonRetriableErrors provides a list of default errors, that cleint will not retry on

Functions

func ExpandFolder

func ExpandFolder(dir string) string

ExpandFolder returns expanded StorageFolder

func HostFolderName

func HostFolderName(host string) string

HostFolderName returns a folder name for a host

func PropagateHeadersFromRequest

func PropagateHeadersFromRequest(ctx context.Context, r *http.Request, headers ...string) context.Context

PropagateHeadersFromRequest will set specified headers in the context, if present in the request

func WithHeaders

func WithHeaders(ctx context.Context, headers map[string]string) context.Context

WithHeaders returns a copy of parent with the provided headers set

Types

type AuthToken

type AuthToken struct {
	Raw          string
	AccessToken  string
	RefreshToken string
	TokenType    string
	DpopJkt      string
	Expires      *time.Time
}

AuthToken provides auth token info

func LoadAuthToken

func LoadAuthToken(dir string) (*AuthToken, string, error)

LoadAuthToken loads .auth_token file

func ParseAuthToken

func ParseAuthToken(rawToken, location string) (*AuthToken, string, error)

ParseAuthToken parses stored token and validates expiration

func (*AuthToken) Expired

func (t *AuthToken) Expired() bool

Expired returns true if expiry is present on the token, and is behind the current time

type BeforeSendRequest

type BeforeSendRequest func(r *http.Request) *http.Request

BeforeSendRequest allows to modify request before it's sent

type Client

type Client struct {
	Name             string
	Policy           Policy // Rery policy for http requests
	EnvAuthTokenName string

	Config ClientConfig
	// contains filtered or unexported fields
}

Client is custom implementation of http.Client

func Default

func Default(host string) (*Client, error)

Default creates a default Client for the given host

func LoadClient

func LoadClient(file string) (*Client, error)

LoadClient returns new Client

func New

func New(cfg ClientConfig, opts ...ClientOption) (*Client, error)

New creates a new Client

func NewForHost

func NewForHost(cfg, host string) (*Client, error)

New returns new Client

func (*Client) AddHeader

func (c *Client) AddHeader(header, value string) *Client

AddHeader adds additional header to the request

func (*Client) CurrentHost

func (c *Client) CurrentHost() string

CurrentHost returns the current host

func (*Client) DecodeResponse

func (c *Client) DecodeResponse(resp *http.Response, body interface{}) (http.Header, int, error)

DecodeResponse will look at the http response, and map it back to either the body parameters, or to an error [retrying rate limit errors should be done before this]

func (*Client) Delete

func (c *Client) Delete(ctx context.Context, path string, body interface{}) (http.Header, int, error)

Delete removes the supplied resource using the current selected cluster member [typically the leader], it will decode the response payload into the supplied body parameter. it returns the HTTP status code, and an optional error for responses with status codes >= 300 it will try and convert the response into an go error. If configured, this call will wait & retry on rate limit and leader election errors path should be an absolute URI path, i.e. /foo/bar/baz

func (*Client) Do

func (c *Client) Do(r *http.Request) (*http.Response, error)

Do wraps calling an HTTP method with retries.

func (*Client) Get

func (c *Client) Get(ctx context.Context, path string, body interface{}) (http.Header, int, error)

Get fetches the supplied resource using the current selected cluster member [typically the leader], it will decode the response payload into the supplied body parameter. it returns the HTTP status code, and an optional error for responses with status codes >= 300 it will try and convert the response into an go error. If configured, this call will wait & retry on rate limit and leader election errors path should be an absolute URI path, i.e. /foo/bar/baz

func (*Client) GetNonceProvider

func (c *Client) GetNonceProvider() NonceProvider

GetNonceProvider returns nonce provider.

func (*Client) HTTPClient

func (c *Client) HTTPClient() *http.Client

HTTPClient returns undelying http.Client

func (*Client) Head

func (c *Client) Head(ctx context.Context, path string) (http.Header, int, error)

Head makes HEAD request. path should be an absolute URI path, i.e. /foo/bar/baz The client must be configured with the hosts list.

func (*Client) HeadTo

func (c *Client) HeadTo(ctx context.Context, host string, path string) (http.Header, int, error)

HeadTo makes HEAD request against the specified hosts. The supplied hosts are tried in order until one succeeds.

host should include all the protocol/host/port preamble, e.g. https://foo.bar:3444 path should be an absolute URI path, i.e. /foo/bar/baz

func (*Client) Post

func (c *Client) Post(ctx context.Context, path string, requestBody interface{}, responseBody interface{}) (http.Header, int, error)

Post makes an HTTP POST to the supplied path. The HTTP response will be decoded into reponseBody, and the status code (and potentially an error) returned. It'll try and map errors (statusCode >= 300) into a go error, waits & retries for rate limiting errors will be applied based on the client config. path should be an absolute URI path, i.e. /foo/bar/baz

func (*Client) Put

func (c *Client) Put(ctx context.Context, path string, requestBody interface{}, responseBody interface{}) (http.Header, int, error)

Put makes an HTTP PUT to the supplied path. The HTTP response will be decoded into reponseBody, and the status code (and potentially an error) returned. It'll try and map errors (statusCode >= 300) into a go error, waits & retries for rate limiting errors will be applied based on the client config. path should be an absolute URI path, i.e. /foo/bar/baz

func (*Client) Request

func (c *Client) Request(ctx context.Context, method string, host string, path string, requestBody interface{}, responseBody interface{}) (http.Header, int, error)

Request sends request to the specified hosts. The supplied hosts are tried in order until one succeeds. It will decode the response payload into the supplied body parameter. It returns the HTTP headers, status code, and an optional error. For responses with status codes >= 300 it will try and convert the response into a Go error. If configured, this call will apply retry logic.

hosts should include all the protocol/host/port preamble, e.g. https://foo.bar:3444 path should be an absolute URI path, i.e. /foo/bar/baz requestBody can be io.Reader, []byte, or an object to be JSON encoded responseBody can be io.Writer, or a struct to decode JSON into.

func (*Client) RequestURL

func (c *Client) RequestURL(ctx context.Context, method, rawURL string, requestBody interface{}, responseBody interface{}) (http.Header, int, error)

RequestURL is similar to Request but uses raw URL to one host

func (*Client) SetNonceProvider

func (c *Client) SetNonceProvider(provider NonceProvider)

SetNonceProvider modifies nonce provider.

func (*Client) Storage

func (c *Client) Storage() *Storage

Storage returns the current storage

func (*Client) WithAuthorization

func (c *Client) WithAuthorization(storage *Storage) error

WithAuthorization sets Authorization token

func (*Client) WithBeforeSendRequest

func (c *Client) WithBeforeSendRequest(hook BeforeSendRequest) *Client

WithBeforeSendRequest allows to specify a hook to modify request before it's sent

func (*Client) WithCallerIdentity added in v0.17.0

func (c *Client) WithCallerIdentity(ci credentials.CallerIdentity) *Client

WithCallerIdentity allows to specify token provider to modify request before it's sent

func (*Client) WithDNSServer

func (c *Client) WithDNSServer(dns string) *Client

WithDNSServer modifies DNS server. dns must be specified in <host>:<port> format

func (*Client) WithHeaders

func (c *Client) WithHeaders(headers map[string]string) *Client

WithHeaders adds additional headers to the request

func (*Client) WithHost

func (c *Client) WithHost(host string) *Client

WithHost sets the host

func (*Client) WithName

func (c *Client) WithName(name string) *Client

WithName modifies client's name for logging purposes.

func (*Client) WithNonce

func (c *Client) WithNonce(path, headerName string)

WithNonce creates default nonce provider.

func (*Client) WithPolicy

func (c *Client) WithPolicy(policy Policy) *Client

WithPolicy modifies retriable policy.

func (*Client) WithTLS

func (c *Client) WithTLS(tlsConfig *tls.Config) *Client

WithTLS modifies TLS configuration.

func (*Client) WithTimeout

func (c *Client) WithTimeout(timeout time.Duration) *Client

WithTimeout modifies HTTP client timeout.

func (*Client) WithTransport

func (c *Client) WithTransport(transport http.RoundTripper) *Client

WithTransport modifies HTTP Transport configuration.

func (*Client) WithUserAgent added in v0.22.0

func (c *Client) WithUserAgent(name string) *Client

WithUserAgent adds User-Agent, X-CLIENT-HOSTNAME, X-CLIENT-IP headers.

type ClientConfig

type ClientConfig struct {
	Host string `json:"host,omitempty" yaml:"host,omitempty"`

	// LegacyHosts are for compat with previous config
	LegacyHosts []string `json:"hosts,omitempty" yaml:"hosts,omitempty"`

	// TLS provides TLS config for the client
	TLS *TLSInfo `json:"tls,omitempty" yaml:"tls,omitempty"`

	// Request provides Request Policy
	Request *RequestPolicy `json:"request,omitempty" yaml:"request,omitempty"`

	// StorageFolder specifies the root folder for keys and token.
	StorageFolder string `json:"storage_folder,omitempty" yaml:"storage_folder,omitempty"`

	// EnvNameAuthToken specifies os.Env name for the Authorization token.
	// if the token is DPoP, then a correponding JWK must be found in StorageFolder
	EnvAuthTokenName string `json:"auth_token_env_name,omitempty" yaml:"auth_token_env_name,omitempty"`
}

ClientConfig of the client, per specific host

func (*ClientConfig) Storage

func (c *ClientConfig) Storage() *Storage

type ClientOption

type ClientOption interface {
	// contains filtered or unexported methods
}

A ClientOption modifies the default behavior of Client.

func WithBeforeSendRequest

func WithBeforeSendRequest(hook BeforeSendRequest) ClientOption

WithBeforeSendRequest allows to specify a hook to modify request before it's sent

func WithCallerIdentity added in v0.22.0

func WithCallerIdentity(ci credentials.CallerIdentity) ClientOption

WithCallerIdentity allows to specify token provider to modify request before it's sent

func WithDNSServer

func WithDNSServer(dns string) ClientOption

WithDNSServer is a ClientOption that allows to use custom dns server for resolution dns server must be specified in <host>:<port> format

retriable.New(retriable.WithDNSServer(dns))

This option cannot be provided for constructors which produce result objects. Note that WithDNSServer applies changes to http client Transport object and hence if used in conjuction with WithTransport method, WithDNSServer should be called after WithTransport is called.

retriable.New(retriable.WithTransport(t).WithDNSServer(dns))

func WithHost

func WithHost(host string) ClientOption

WithHost is a ClientOption that allows to set the host list.

retriable.New(retriable.WithHost(host))

func WithName

func WithName(name string) ClientOption

WithName is a ClientOption that specifies client's name for logging purposes.

retriable.New(retriable.WithName("tlsclient"))

This option cannot be provided for constructors which produce result objects.

func WithPolicy

func WithPolicy(policy Policy) ClientOption

WithPolicy is a ClientOption that specifies retriable policy.

retriable.New(retriable.WithPolicy(p))

This option cannot be provided for constructors which produce result objects.

func WithTLS

func WithTLS(tlsConfig *tls.Config) ClientOption

WithTLS is a ClientOption that specifies TLS configuration.

retriable.New(retriable.WithTLS(t))

This option cannot be provided for constructors which produce result objects.

func WithTimeout

func WithTimeout(timeout time.Duration) ClientOption

WithTimeout is a ClientOption that specifies HTTP client timeout.

retriable.New(retriable.WithTimeout(t))

This option cannot be provided for constructors which produce result objects.

func WithTransport

func WithTransport(transport http.RoundTripper) ClientOption

WithTransport is a ClientOption that specifies HTTP Transport configuration.

retriable.New(retriable.WithTransport(t))

This option cannot be provided for constructors which produce result objects.

func WithUserAgent added in v0.22.0

func WithUserAgent(name string) ClientOption

WithUserAgent adds User-Agent, X-CLIENT-HOSTNAME, X-CLIENT-IP headers.

type Config

type Config struct {
	Clients map[string]*ClientConfig `json:"clients,omitempty" yaml:"clients,omitempty"`
}

Config of the client

type DeleteRequester

type DeleteRequester interface {
	// Delete makes a DELETE request,
	// path should be an absolute URI path, i.e. /foo/bar/baz
	// the resulting HTTP body will be decoded into the supplied body parameter, and the
	// http status code returned.
	Delete(ctx context.Context, path string, body interface{}) (http.Header, int, error)
}

DeleteRequester defines HTTP Delete interface

type Factory

type Factory struct {
	// contains filtered or unexported fields
}

Factory provides factory for retriable client for a specific host

func LoadFactory

func LoadFactory(file string) (*Factory, error)

LoadFactory returns new Factory

func NewFactory

func NewFactory(cfg Config) (*Factory, error)

NewFactory returns new Factory

func (*Factory) ConfigForHost

func (f *Factory) ConfigForHost(hostname string) *ClientConfig

ConfigForHost returns config for host

func (*Factory) CreateClient

func (f *Factory) CreateClient(clientName string) (*Client, error)

CreateClient returns Client for a specified client name. If the name is not found in the configuration, a client with default settings will be returned.

func (*Factory) ForHost

func (f *Factory) ForHost(hostname string) (*Client, error)

ForHost returns Client for specified host name. If the name is not found in the configuration, a client with default settings will be returned.

type GenericHTTP

type GenericHTTP interface {
	// Request sends request to the specified hosts.
	// The supplied hosts are tried in order until one succeeds.
	// It will decode the response payload into the supplied body parameter.
	// It returns the HTTP headers, status code, and an optional error.
	// For responses with status codes >= 300 it will try and convert the response
	// into a Go error.
	// If configured, this call will apply retry logic.
	//
	// host should include all the protocol/host/port preamble, e.g. https://foo.bar:3444
	// path should be an absolute URI path, i.e. /foo/bar/baz
	// requestBody can be io.Reader, []byte, or an object to be JSON encoded
	// responseBody can be io.Writer, or a struct to decode JSON into.
	Request(ctx context.Context, method string, host string, path string, requestBody interface{}, responseBody interface{}) (http.Header, int, error)

	// RequestURL is similar to Request but uses raw URL to one host
	RequestURL(ctx context.Context, method, rawURL string, requestBody interface{}, responseBody interface{}) (http.Header, int, error)

	// HeadTo makes HEAD request against the specified hosts.
	// The supplied hosts are tried in order until one succeeds.
	//
	// host should include all the protocol/host/port preamble, e.g. https://foo.bar:3444
	// path should be an absolute URI path, i.e. /foo/bar/baz
	HeadTo(ctx context.Context, host string, path string) (http.Header, int, error)
}

GenericHTTP defines a number of generalized HTTP request handling wrappers

type GetRequester

type GetRequester interface {
	// Get makes a GET request,
	// path should be an absolute URI path, i.e. /foo/bar/baz
	// the resulting HTTP body will be decoded into the supplied body parameter, and the
	// http status code returned.
	// The client must be configured with the hosts list.
	Get(ctx context.Context, path string, body interface{}) (http.Header, int, error)
}

GetRequester defines HTTP Get interface

type HTTPClient

HTTPClient defines a number of generalized HTTP request handling wrappers

type HTTPClientWithNonce

type HTTPClientWithNonce interface {
	GenericHTTP
	HTTPClient
	NonceRequester
}

HTTPClientWithNonce defines a HTTPClient with NonceRequester

type HeadRequester

type HeadRequester interface {
	// Head makes HEAD request.
	// path should be an absolute URI path, i.e. /foo/bar/baz
	// The client must be configured with the hosts list.
	Head(ctx context.Context, path string) (http.Header, int, error)
}

HeadRequester defines HTTP Head interface

type KeyInfo

type KeyInfo struct {
	KeySize    int
	Type       string
	Algo       string
	Thumbprint string
	Key        *jose.JSONWebKey
}

KeyInfo specifies key info

func NewKeyInfo

func NewKeyInfo(k *jose.JSONWebKey) (*KeyInfo, error)

NewKeyInfo returns *keyInfo

type NonceProvider

type NonceProvider interface {
	// Nonce returns new nonce by fetching from server
	Nonce() (string, error)
	// SetFromHeader extracts Nonce from a HTTP response headers
	SetFromHeader(hdr http.Header)
}

NonceProvider specifies interface for Nonces

func NewNonceProvider

func NewNonceProvider(client HTTPClient, noncePath, headerName string) NonceProvider

NewNonceProvider returns default nonce provider

type NonceRequester

type NonceRequester interface {
	SetNonceProvider(provider NonceProvider)
	GetNonceProvider() NonceProvider
	// WithNonce creates nonce provider out of the given header name and path
	WithNonce(path, headerName string)
}

NonceRequester defines HTTP Nonce interface

type Policy

type Policy struct {

	// Retries specifies a map of HTTP Status code to ShouldRetry function,
	// 0 status code indicates a connection related error (network, TLS, DNS etc.)
	Retries map[int]ShouldRetry

	// Maximum number of retries.
	TotalRetryLimit int

	RequestTimeout time.Duration

	NonRetriableErrors []string
}

Policy represents the retriable policy

func DefaultPolicy

func DefaultPolicy() Policy

DefaultPolicy returns default policy

func (*Policy) ShouldRetry

func (p *Policy) ShouldRetry(r *http.Request, resp *http.Response, err error, retries int) (bool, time.Duration, string)

ShouldRetry returns if connection should be retried

type PostRequester

type PostRequester interface {
	// Post makes an HTTP POST to the supplied path, serializing requestBody to json and sending
	// that as the HTTP body. the HTTP response will be decoded into reponseBody, and the status
	// code (and potentially an error) returned. It'll try and map errors (statusCode >= 300)
	// into a go error, waits & retries for rate limiting errors will be applied based on the
	// client config.
	// path should be an absolute URI path, i.e. /foo/bar/baz
	Post(ctx context.Context, path string, requestBody interface{}, responseBody interface{}) (http.Header, int, error)
}

PostRequester defines HTTP Post interface

type PutRequester

type PutRequester interface {
	// Put makes an HTTP PUT to the supplied path, serializing requestBody to json and sending
	// that as the HTTP body. the HTTP response will be decoded into reponseBody, and the status
	// code (and potentially an error) returned. It'll try and map errors (statusCode >= 300)
	// into a go error, waits & retries for rate limiting errors will be applied based on the
	// client config.
	// path should be an absolute URI path, i.e. /foo/bar/baz
	Put(ctx context.Context, path string, requestBody interface{}, responseBody interface{}) (http.Header, int, error)
}

PutRequester defines HTTP Put interface

type ReaderFunc

type ReaderFunc func() (io.Reader, error)

ReaderFunc is the type of function that can be given natively to NewRequest

type Request

type Request struct {

	// Embed an HTTP request directly. This makes a *Request act exactly
	// like an *http.Request so that all meta methods are supported.
	*http.Request
	// contains filtered or unexported fields
}

Request wraps the metadata needed to create HTTP requests.

func NewRequest

func NewRequest(method, url string, rawBody io.ReadSeeker) (*Request, error)

NewRequest creates a new wrapped request.

func (*Request) AddHeader

func (r *Request) AddHeader(header, value string) *Request

AddHeader adds additional header to the request

func (*Request) WithHeaders

func (r *Request) WithHeaders(headers map[string]string) *Request

WithHeaders adds additional headers to the request

type RequestPolicy

type RequestPolicy struct {
	RetryLimit int           `json:"retry_limit,omitempty" yaml:"retry_limit,omitempty"`
	Timeout    time.Duration `json:"timeout,omitempty" yaml:"timeout,omitempty"`
}

RequestPolicy contains configuration info for Request policy

type Requestor

type Requestor interface {
	Do(r *http.Request) (*http.Response, error)
}

Requestor defines interface to make HTTP calls

type ShouldRetry

type ShouldRetry func(r *http.Request, resp *http.Response, err error, retries int) (bool, time.Duration, string)

ShouldRetry specifies a policy for handling retries. It is called following each request with the response, error values returned by the http.Client and the number of already made retries. If ShouldRetry returns false, the Client stops retrying and returns the response to the caller. The Client will close any response body when retrying, but if the retriable is aborted it is up to the caller to properly close any response body before returning.

func DefaultShouldRetryFactory

func DefaultShouldRetryFactory(limit int, wait time.Duration, reason string) ShouldRetry

DefaultShouldRetryFactory returns default ShouldRetry

type Storage

type Storage struct {
	// contains filtered or unexported fields
}

Storage provides Client storage

func OpenStorage

func OpenStorage(baseFolder, host, envAuthTokenName string) *Storage

OpenStorage returns Storage

func (*Storage) Clean

func (c *Storage) Clean()

Clean removes all stored files

func (*Storage) ListKeys

func (c *Storage) ListKeys() ([]*KeyInfo, error)

ListKeys returns list of DPoP keys in the storage

func (*Storage) LoadAuthToken

func (c *Storage) LoadAuthToken() (*AuthToken, string, error)

LoadAuthToken returns LoadAuthToken

func (*Storage) LoadKey

func (c *Storage) LoadKey(label string) (*jose.JSONWebKey, string, error)

LoadKey returns *jose.JSONWebKey

func (*Storage) SaveAuthToken

func (c *Storage) SaveAuthToken(token string) (string, error)

SaveAuthToken persists auth token the token format can be as opaque string, or as form encoded access_token={token}&exp={unix_time}&dpop_jkt={jkt}&token_type={Bearer|DPoP}

func (*Storage) SaveKey

func (c *Storage) SaveKey(k *jose.JSONWebKey) (string, error)

SaveKey saves the key to storage

type TLSInfo

type TLSInfo struct {
	// CertFile specifies location of the cert
	CertFile string `json:"cert,omitempty" yaml:"cert,omitempty"`

	// KeyFile specifies location of the key
	KeyFile string `json:"key,omitempty" yaml:"key,omitempty"`

	// TrustedCAFile specifies location of the trusted Root file
	TrustedCAFile string `json:"trusted_ca,omitempty" yaml:"trusted_ca,omitempty"`
}

TLSInfo contains configuration info for the TLS

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL