Documentation
¶
Overview ¶
Package httpclient provides a shared HTTP client for all external API calls. The client is safe for concurrent use and reuses connections. Call Init once during startup to set the timeout; the default is 10s.
Index ¶
- Constants
- Variables
- func Do(req *http.Request) (*http.Response, error)
- func DownloadBytesCtx(ctx context.Context, url string, maxBytes int64) ([]byte, error)
- func DownloadCtx(ctx context.Context, url, destPath string, maxBytes int64) (int64, error)
- func GetJSON(url string) ([]byte, error)
- func GetJSONCtx(ctx context.Context, url string) ([]byte, error)
- func Init(timeout time.Duration)
- func IsTransport(err error) bool
- func IsTruncated(err error) bool
- func SetTransport(rt http.RoundTripper)
- func SetUserAgent(version string)
- func Status(err error) int
- func Truncate(s string, maxLen int) string
- type StatusError
- type TransportError
- type TruncatedError
Constants ¶
const DefaultMaxDownloadSize = 200 << 20
DefaultMaxDownloadSize caps a single DownloadCtx response at 200 MB — comfortably larger than any truestamp release tarball today, small enough to prevent a runaway redirect from filling the disk.
const MaxResponseSize = 1 << 20
MaxResponseSize limits HTTP response bodies to 1 MB to prevent OOM.
Variables ¶
var ErrRedirectDowngrade = errors.New("refusing redirect that downgrades https to http")
ErrRedirectDowngrade is returned (wrapped in a *url.Error by net/http) when a server tries to redirect an https request to a plaintext http URL. Following such a redirect would strip TLS mid-chain, which for the keyring fetch in particular is a total compromise: an attacker who can substitute the keyring can substitute signing keys, and every downstream signature then validates against their key. See VerifyKeyring's threat note in internal/external/keyring.go.
Functions ¶
func Do ¶
Do executes an HTTP request using the shared client. The request's existing context.Context (if any) is respected; callers that want cancellation should attach one via http.Request.WithContext before calling. If SetUserAgent has been called and the request has no User-Agent header, the configured value is applied.
func DownloadBytesCtx ¶ added in v0.3.1
DownloadBytesCtx is like DownloadCtx but returns the body in memory. Intended for small artifacts (checksums.txt, signature bundles) that exceed MaxResponseSize occasionally but are still known to be small (<1 MB). Pass 0 for maxBytes to default to 1 MB.
func DownloadCtx ¶ added in v0.3.1
DownloadCtx streams the body of a GET request to destPath. The destination is created (or truncated) with 0644 permissions. The response body is read through an io.LimitReader capped at maxBytes; pass 0 (or a negative value) to use DefaultMaxDownloadSize.
Unlike GetJSONCtx, this function is safe for multi-MB responses and never buffers the full body in memory.
Returns the number of bytes written on success.
func GetJSON ¶
GetJSON performs a GET request with context.Background and returns the response body. Prefer GetJSONCtx when a cancellable context is available (e.g. from Cobra's cmd.Context()).
func GetJSONCtx ¶ added in v0.3.0
GetJSONCtx performs a context-aware GET request and returns the response body. Errors are typed: *TransportError before a response exists, *StatusError for a non-2xx status, *TruncatedError for a body over MaxResponseSize. Their Error() strings are unchanged from the untyped versions they replaced.
func Init ¶
Init creates a new HTTP client with the given timeout. Must be called once during startup before any external calls. The redirect policy in [checkRedirect] is reinstalled here; building a bare http.Client instead would silently drop it.
func IsTransport ¶ added in v0.12.0
IsTransport reports whether err is (or wraps) a *TransportError.
func IsTruncated ¶ added in v0.12.0
IsTruncated reports whether err is (or wraps) a *TruncatedError.
func SetTransport ¶ added in v0.9.0
func SetTransport(rt http.RoundTripper)
SetTransport installs rt as the round-tripper for the shared client. The CLI uses it to layer the auth package's reactive 401 → refresh → retry-once behavior on top of the default transport. Call after Init, which replaces the client.
func SetUserAgent ¶ added in v0.7.0
func SetUserAgent(version string)
SetUserAgent configures the User-Agent header stamped onto every outbound request through Do. Typical value: "truestamp-cli/<version> (<os>/<arch>)". Pass an empty string to disable the override (requests keep whatever UA the caller set, or Go's default).
Types ¶
type StatusError ¶ added in v0.12.0
type StatusError struct {
StatusCode int
URL string
Body string // truncated to 80 bytes
HTML bool // the body looked like an HTML error page
}
StatusError is returned for any non-2xx response. It preserves the status code so a caller can tell a definitive answer (404) from an availability problem (429, 5xx).
func (*StatusError) Error ¶ added in v0.12.0
func (e *StatusError) Error() string
type TransportError ¶ added in v0.12.0
TransportError wraps a failure that happened before any HTTP response was received: request construction, DNS resolution, dial, TLS handshake, client timeout, context cancellation, or a body that could not be read. A verifier must report these as `skip` rather than `fail` (whitepaper Appendix E.17/E.18/E.21/E.22), so the distinction has to survive to the call site instead of collapsing into one opaque error.
func (*TransportError) Error ¶ added in v0.12.0
func (e *TransportError) Error() string
func (*TransportError) Unwrap ¶ added in v0.12.0
func (e *TransportError) Unwrap() error
type TruncatedError ¶ added in v0.12.0
TruncatedError is returned when a 2xx body exceeded MaxResponseSize. Without it the cut-off bytes reach the caller's JSON decoder and surface as a syntax error, which reads as "the server sent junk" when the real cause is our own cap.
func (*TruncatedError) Error ¶ added in v0.12.0
func (e *TruncatedError) Error() string