client

package
v0.11.0 Latest Latest
Warning

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

Go to latest
Published: Oct 19, 2026 License: MIT Imports: 14 Imported by: 5

Documentation

Overview

Package client provides an HTTP client with retry logic for registry APIs.

Index

Constants

This section is empty.

Variables

View Source
var ErrNotFound = errors.New("not found")

ErrNotFound is returned when a package or version is not found.

View Source
var ErrUpstreamHeld = errors.New("upstream requests are held by rate limiting")

ErrUpstreamHeld marks a request refused locally during a rate-limit hold.

Functions

func BuildURLs

func BuildURLs(urls URLBuilder, name, version string) map[string]string

BuildURLs returns a map of all non-empty URLs for a package. Keys are "registry", "download", "docs", and "purl".

Types

type BaseURLs

type BaseURLs struct {
	RegistryFn      func(name, version string) string
	DownloadFn      func(name, version string) string
	DocumentationFn func(name, version string) string
	PURLFn          func(name, version string) string
}

BaseURLs provides a default URLBuilder implementation.

func (*BaseURLs) Documentation

func (b *BaseURLs) Documentation(name, version string) string

func (*BaseURLs) Download

func (b *BaseURLs) Download(name, version string) string

func (*BaseURLs) PURL

func (b *BaseURLs) PURL(name, version string) string

func (*BaseURLs) Registry

func (b *BaseURLs) Registry(name, version string) string

type Client

type Client struct {
	HTTPClient  *http.Client
	UserAgent   string
	MaxRetries  int
	BaseDelay   time.Duration
	RateLimiter RateLimiter
}

Client is an HTTP client with retry logic for registry APIs.

func DefaultClient

func DefaultClient() *Client

DefaultClient returns a client with sensible defaults.

func NewClient

func NewClient(opts ...Option) *Client

NewClient creates a new client with the given options.

func (*Client) GetBody

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

GetBody fetches a URL and returns the response body.

func (*Client) GetJSON

func (c *Client) GetJSON(ctx context.Context, url string, v any) error

GetJSON fetches a URL and decodes the JSON response into v.

func (*Client) GetText

func (c *Client) GetText(ctx context.Context, url string) (string, error)

GetText fetches a URL and returns the response body as a string.

func (*Client) Head

func (c *Client) Head(ctx context.Context, url string) (int, error)

Head sends a HEAD request and returns the status code.

func (*Client) WithRateLimiter

func (c *Client) WithRateLimiter(rl RateLimiter) *Client

WithRateLimiter returns a copy of the client with the given rate limiter.

func (*Client) WithUserAgent

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

WithUserAgent returns a copy of the client with the given user agent.

type HTTPError

type HTTPError struct {
	StatusCode int
	URL        string
	Body       string
}

HTTPError represents an HTTP error response.

func (*HTTPError) Error

func (e *HTTPError) Error() string

func (*HTTPError) IsNotFound

func (e *HTTPError) IsNotFound() bool

IsNotFound returns true if the error represents a 404 response.

type HeldError added in v0.10.0

type HeldError struct {
	Host       string
	Until      time.Time
	RetryAfter time.Duration
}

HeldError is returned in place of a response while a host is held.

func (*HeldError) Error added in v0.10.0

func (e *HeldError) Error() string

func (*HeldError) Is added in v0.10.0

func (e *HeldError) Is(target error) bool

type HoldEvent added in v0.10.0

type HoldEvent struct {
	Host       string
	Until      time.Time
	RetryAfter time.Duration
	FromHeader bool
}

HoldEvent describes a rate-limit response, including any longer active hold.

type NotFoundError

type NotFoundError struct {
	Ecosystem string
	Name      string
	Version   string
}

NotFoundError wraps ErrNotFound with additional context.

func (*NotFoundError) Error

func (e *NotFoundError) Error() string

func (*NotFoundError) Unwrap

func (e *NotFoundError) Unwrap() error

type Option

type Option func(*Client)

Option configures a Client.

func WithHTTPClient

func WithHTTPClient(h *http.Client) Option

WithHTTPClient swaps in a caller-supplied *http.Client. Use this when the application has its own connection pool, mTLS config, or auth-injecting transport that other Options like WithTimeout can't express. The supplied client's Timeout, Jar, and Transport are preserved as-is.

func WithMaxRetries

func WithMaxRetries(n int) Option

WithMaxRetries sets the maximum number of retries.

func WithSafeHTTP

func WithSafeHTTP() Option

WithSafeHTTP wraps the client's underlying *http.Client with the safehttp transport: dial-time IP gate (rejects loopback, RFC1918, CGNAT, link-local, multicast, unspecified), redirect chain capped at 10, non-http(s) schemes rejected on redirect. DNS is resolved at dial time and the connection dials the resolved IP directly so a rebind between resolve and connect cannot escape the gate. Suitable for any code path that fetches from URLs an attacker might control (a malicious registry response, a manifest-supplied URL, a redirect target).

func WithTimeout

func WithTimeout(d time.Duration) Option

WithTimeout sets the HTTP client timeout.

func WithTransport

func WithTransport(rt http.RoundTripper) Option

WithTransport replaces the underlying http.RoundTripper without touching the Client's other settings (timeout, jar, etc.). Useful for wrapping the transport in middleware (auth, logging, retry, rate-limit) while keeping the rest of the configured shape intact.

type RateLimitError

type RateLimitError struct {
	RetryAfter int // seconds
}

RateLimitError is returned when the registry rate limits requests.

func (*RateLimitError) Error

func (e *RateLimitError) Error() string

type RateLimitGate added in v0.10.0

type RateLimitGate struct {

	// Set callbacks before use. They run outside the lock and may run concurrently.
	OnHold    func(HoldEvent)
	OnRelease func(host string)
	// contains filtered or unexported fields
}

RateLimitGate holds a host after a 429 or a 503 with Retry-After. Limited responses pass through; requests during a hold return HeldError. The first non-limited response after expiry releases the hold.

func NewRateLimitGate added in v0.10.0

func NewRateLimitGate(base http.RoundTripper) *RateLimitGate

NewRateLimitGate wraps base. A nil base uses http.DefaultTransport.

func (*RateLimitGate) Held added in v0.10.0

func (g *RateLimitGate) Held(rawURL string) error

Held returns a *HeldError when requests to rawURL's host are being held, and nil otherwise. It is safe to call on a nil gate.

func (*RateLimitGate) Holds added in v0.10.0

func (g *RateLimitGate) Holds() map[string]time.Time

Holds returns the hosts currently held and when each hold ends. It is safe to call on a nil gate.

func (*RateLimitGate) RoundTrip added in v0.10.0

func (g *RateLimitGate) RoundTrip(req *http.Request) (*http.Response, error)

RoundTrip implements http.RoundTripper.

type RateLimiter

type RateLimiter interface {
	Wait(ctx context.Context) error
}

RateLimiter controls request pacing.

type URLBuilder

type URLBuilder interface {
	Registry(name, version string) string
	Download(name, version string) string
	Documentation(name, version string) string
	PURL(name, version string) string
}

URLBuilder constructs URLs for a registry.

Jump to

Keyboard shortcuts

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