fetch

package
v0.2.0 Latest Latest
Warning

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

Go to latest
Published: Aug 19, 2026 License: Apache-2.0 Imports: 12 Imported by: 0

Documentation

Overview

Package fetch retrieves a remote image on behalf of a request, under the server-side request forgery guards docs/SECURITY.md Layer 4 promises.

style.logo may name a URL, and a service that dereferences a URL chosen by an untrusted caller is a request-forgery primitive: the caller picks the destination, and the server brings a routing table, a place inside the network perimeter, and often an identity the caller does not have. The guards are therefore deny-by-default and layered:

  • https only, so no caller can reach file:, gopher:, or a plaintext port;
  • an exact host allowlist, empty by default, so nothing is reachable at all until an operator names it;
  • resolution and address vetting done here, in front of the dialler, and a dial to the vetted address rather than to the name, so DNS cannot change between the check and the connection;
  • no redirects, because following one means re-running every check above on the new target and refusing is far easier to get right;
  • caps on time and on bytes, the byte cap checked twice, because a host that answers slowly or endlessly is a denial-of-service amplifier.

Errors from this package never carry the underlying network error. A dial failure names the address it dialled, and that address is precisely what these guards exist to keep from the caller.

Index

Constants

This section is empty.

Variables

View Source
var (
	// ErrDisabled means the options carry no time or byte budget, which is
	// what an unconfigured fetcher looks like.
	ErrDisabled = errors.New("remote fetching is not configured")
	// ErrNotAllowed means the host is not on the allowlist. An empty
	// allowlist puts every host in this state.
	ErrNotAllowed = errors.New("host is not on the fetch allowlist")
	// ErrPrivateAddress means the host resolved to an address that is not
	// publicly routable — loopback, RFC 1918, link-local, and the rest.
	ErrPrivateAddress = errors.New("host resolves to a non-public address")
	// ErrUnresolved means the host has no address at all.
	ErrUnresolved = errors.New("host could not be resolved")
	// ErrTooLarge means the response is bigger than MaxBytes.
	ErrTooLarge = errors.New("remote image exceeds the size cap")
	// ErrBadStatus means the host answered with a non-2xx status, refused a
	// redirect, or could not be reached at all.
	ErrBadStatus = errors.New("remote image could not be retrieved")
	// ErrBadScheme means the URL is not an https URL.
	ErrBadScheme = errors.New("url scheme is not https")
	// ErrTimeout means the fetch did not finish inside Timeout.
	ErrTimeout = errors.New("remote image fetch timed out")
	// ErrNotImage means the body is not an image, whatever the host claimed
	// in its Content-Type.
	ErrNotImage = errors.New("remote resource is not an image")
)

Sentinel errors. The HTTP layer maps these onto stable error codes, so a reworded message can never change what a client sees.

Functions

func Enabled

func Enabled(o Options) bool

Enabled reports whether o could fetch anything at all, so that a caller can tell "switched off" from "switched on and misconfigured" and say so.

func Fetch

func Fetch(ctx context.Context, rawURL string, o Options) ([]byte, string, error)

Fetch retrieves a remote image under the SSRF guards.

It returns the body and the media type sniffed from that body — never the type the host declared. The caller gets bytes it can decode or an error it can map; it never gets the address that was dialled.

Types

type Options

type Options struct {
	// Allowlist is the set of hosts that may be fetched from. Matching is
	// exact on the whole host, case-insensitive, and ignores the port.
	Allowlist []string
	// Timeout bounds the entire operation: resolution, connection, and body.
	Timeout time.Duration
	// MaxBytes caps the response body.
	MaxBytes int64
	// contains filtered or unexported fields
}

Options bounds a fetch.

The zero value fetches nothing, which is the intended default: an empty allowlist means no host is reachable, and a zero timeout or byte cap means the feature was never configured.

Jump to

Keyboard shortcuts

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