httpclient

package
v0.11.0 Latest Latest
Warning

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

Go to latest
Published: Oct 29, 2026 License: AGPL-3.0 Imports: 15 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.

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".

Jump to

Keyboard shortcuts

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