httpclient

package
v0.40.0 Latest Latest
Warning

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

Go to latest
Published: Nov 2, 2026 License: AGPL-3.0 Imports: 17 Imported by: 0

Documentation

Overview

Package httpclient is the only way out to the network: every source and registry fetches through a Client (ADR 0002).

A Client sends GET requests over HTTPS to an exact list of hosts, follows a redirect only to one of them, bounds every phase of a call with its own timeout, refuses a body over a size limit and retries 429 and 5xx answers with exponential backoff, full jitter and Retry-After.

A Client never uses a proxy, even when HTTP_PROXY or HTTPS_PROXY is set: an inherited proxy would see every query and widen the egress surface without anyone choosing it. Filtering egress belongs to the network.

Index

Constants

View Source
const (
	DefaultTimeout               = 30 * time.Second
	DefaultDialTimeout           = 5 * time.Second
	DefaultTLSHandshakeTimeout   = 5 * time.Second
	DefaultResponseHeaderTimeout = 10 * time.Second
	DefaultMaxBodyBytes          = 16 << 20
	DefaultAttempts              = 3
	DefaultBaseBackoff           = 500 * time.Millisecond
	DefaultMaxBackoff            = 30 * time.Second
)

Defaults applied by New to a zero Config field. They are choices, sized for the files and registries listed in docs/sources.md (the largest file, ARCEP MAJNUM, is about 1.1 MB).

View Source
const DefaultUserAgent = "arnakoff (+https://github.com/arnakoff/api)"

DefaultUserAgent identifies Arnakoff to upstreams and points to the project, so an operator who sees the traffic knows whom to contact.

Variables

View Source
var (
	// ErrURLNotAllowed means a URL, or a redirect target, is not HTTPS on an
	// allowed host, or carries credentials. No request was sent to it.
	ErrURLNotAllowed = errors.New("URL not allowed")

	// ErrBodyTooLarge means a response body exceeds Config.MaxBodyBytes.
	ErrBodyTooLarge = errors.New("response body too large")

	// ErrInvalidConfig means New was given a Config it cannot use.
	ErrInvalidConfig = errors.New("invalid HTTP client config")
)

Functions

This section is empty.

Types

type Client

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

Client is an outbound HTTP client restricted to allowed hosts. It is safe for concurrent use.

func New

func New(cfg Config) (*Client, error)

New returns a Client for cfg, or ErrInvalidConfig.

func (*Client) Get

func (c *Client) Get(ctx context.Context, rawURL string) ([]byte, error)

Get fetches rawURL and returns its body. It returns ErrURLNotAllowed without sending anything when rawURL is not HTTPS on an allowed host, ErrBodyTooLarge, a *StatusError for a non-2xx answer, or the error of the transport or of ctx.

func (*Client) Post added in v0.19.0

func (c *Client) Post(ctx context.Context, rawURL, contentType string, body []byte) error

Post sends body to rawURL with the given content type and discards the answer. It is retried like Get, so the receiver may get body twice. Its errors, those of Get otherwise, never quote rawURL: a webhook URL carries a secret.

type Config

type Config struct {
	// AllowedHosts are the exact hosts the client may reach, as in URL.Host:
	// "rdap.nic.fr", or "127.0.0.1:8443" with a port. Required.
	AllowedHosts []string

	// UserAgent is sent with every request.
	UserAgent string

	// Timeout bounds a whole Get call: every attempt, every pause between
	// attempts and the reading of the body.
	Timeout time.Duration

	// DialTimeout bounds opening a TCP connection.
	DialTimeout time.Duration

	// TLSHandshakeTimeout bounds the TLS handshake.
	TLSHandshakeTimeout time.Duration

	// ResponseHeaderTimeout bounds the wait for response headers once the
	// request is sent.
	ResponseHeaderTimeout time.Duration

	// MaxBodyBytes is the largest response body Get accepts.
	MaxBodyBytes int64

	// Attempts is the number of tries for a 429 or 5xx answer, the first
	// one included.
	Attempts int

	// BaseBackoff is the ceiling of the first pause between two attempts;
	// the ceiling doubles at each retry, up to MaxBackoff.
	BaseBackoff time.Duration

	// MaxBackoff caps a pause. A Retry-After longer than MaxBackoff ends
	// the retries rather than hammer the upstream sooner than it asked.
	MaxBackoff time.Duration

	// RootCAs are the trusted certificate authorities; nil means the
	// system pool.
	RootCAs *x509.CertPool
}

Config configures a Client. Every zero field but AllowedHosts and RootCAs takes its Default value; a negative one is invalid.

type StatusError

type StatusError struct {
	// StatusCode is the HTTP status of the last response.
	StatusCode int
	// contains filtered or unexported fields
}

StatusError is a response whose status is not 2xx, returned once retries, if any, are over. Match it with errors.As to read StatusCode, for example to read a 404 from a registry as "not found".

func (*StatusError) Error

func (e *StatusError) Error() string

Error returns the status, such as "unexpected HTTP status 404 Not Found".

func (*StatusError) RetryAfter added in v0.20.0

func (e *StatusError) RetryAfter() (time.Duration, bool)

RetryAfter returns the wait the last response asked for in a valid Retry-After header, and false when it had none, so a caller can stay away from an upstream that throttles it.

Directories

Path Synopsis
Package httpclienttest builds httpclient.Client values for tests against an httptest TLS server.
Package httpclienttest builds httpclient.Client values for tests against an httptest TLS server.

Jump to

Keyboard shortcuts

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