httpx

package
v0.5.0 Latest Latest
Warning

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

Go to latest
Published: Jul 3, 2026 License: Apache-2.0 Imports: 13 Imported by: 0

Documentation

Overview

Package httpx provides small HTTP helpers shared across providers.

Index

Constants

This section is empty.

Variables

View Source
var ErrIdleTimeout = errors.New("idle stream timeout")

ErrIdleTimeout is returned by an IdleTimeoutReader when no bytes arrive within the configured idle window — a stalled stream, distinct from a clean io.EOF.

Functions

func DenyInternalRedirect

func DenyInternalRedirect(req *http.Request, via []*http.Request) error

DenyInternalRedirect is an http.Client CheckRedirect that caps the redirect chain and refuses a redirect to a private/loopback/link-local target — closing the redirect → 169.254.169.254 (cloud metadata) SSRF exfil path. It fails CLOSED on an unresolvable target; public redirects are still followed.

It guards only chains that ORIGINATED at a public address — the actual SSRF threat (a public endpoint steered at an internal target). A chain that started internal (an in-cluster model/metrics/logs backend behind a proxy, or a plain http→https / trailing -slash redirect on a private host) is legitimate and is allowed, so the guard never breaks in-cluster traffic. Dial-time DNS-rebinding protection is out of scope.

func DoWithRetry

func DoWithRetry(ctx context.Context, client *http.Client, attempts int, build func() (*http.Request, error)) (*http.Response, error)

DoWithRetry issues build()'s request with bounded backoff, retrying on a network error, HTTP 429, or 5xx — a transient upstream failure shouldn't fail the whole investigation. Other 4xx and 2xx return immediately. build is invoked fresh each attempt so a consumed request body is rebuilt. On a 429 the wait honors the server's Retry-After / retry-after-ms hint (capped); otherwise it uses capped exponential backoff. The wait respects ctx cancellation. The last response (a 429/5xx) is returned so the caller can surface its status.

func NewIdleTimeoutReader added in v0.3.0

func NewIdleTimeoutReader(rc io.ReadCloser, idle time.Duration, onIdle func()) io.ReadCloser

NewIdleTimeoutReader wraps rc so that any Read which stalls for longer than idle fails with ErrIdleTimeout and calls onIdle once. idle <= 0 disables the timeout (rc is returned unwrapped). onIdle may be nil.

func RequestID

func RequestID(h http.Header) string

RequestID returns the first present upstream request-id header (by the precedence in requestIDHeaders), sanitized for safe logging. It returns "" when none is set. The result is operator-trusted correlation metadata — not body content — suitable for an error surfaced at Error level.

func SSEData added in v0.3.0

func SSEData(r io.Reader) iter.Seq2[[]byte, error]

SSEData parses a Server-Sent Events stream and yields each event's concatenated `data:` payload (multiple data: lines in one event are joined with newlines, per the SSE spec). A blank line dispatches the accumulated event; a final event with no trailing blank line is flushed at EOF. Non-data lines (event:, id:, retry:, and `:`-comment lines) are ignored — callers that need the event type read it from the JSON payload. A read error is yielded as the second value (so a dropped stream is observable); io.EOF is treated as a clean end, not an error.

Iteration stops when the consumer breaks or the stream ends. It is the provider's SSE framing primitive; each provider unmarshals the payload into its own event type.

func SanitizeHeader

func SanitizeHeader(s string) string

SanitizeHeader makes an upstream-supplied header value safe to embed in a log line: it drops control characters (anything below 0x20 plus DEL 0x7f, which includes CR/LF/TAB/NUL and ANSI ESC) so the value cannot forge log structure or inject terminal escapes, then caps the length and trims surrounding space.

func SecureClient

func SecureClient(timeout time.Duration) *http.Client

SecureClient returns an http.Client with the given timeout and the DenyInternalRedirect policy. Use it for every outbound call to an operator- or externally-configurable endpoint (model, forge, notifier, metrics/logs) so a redirect can't be steered at an internal address.

func SecureStreamingClient added in v0.3.0

func SecureStreamingClient(responseHeaderTimeout time.Duration) *http.Client

SecureStreamingClient returns an http.Client tuned for consuming a long-lived SSE stream. Unlike SecureClient it has NO flat overall Timeout — a flat deadline would kill a legitimate long completion mid-stream — and instead relies on the request context (for cancellation) plus an idle/read timeout applied by the caller (see NewIdleTimeoutReader). It keeps the DenyInternalRedirect SSRF guard.

responseHeaderTimeout bounds the time spent waiting for the response headers (time-to-first-byte at the protocol level) so a backend that accepts the connection but never replies cannot hang the request before streaming begins; once headers arrive, the body may stream for as long as it stays active.

Types

This section is empty.

Jump to

Keyboard shortcuts

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