transport

package
v0.0.0-...-5c6d8ba Latest Latest
Warning

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

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

Documentation

Overview

Package transport is Polaris's single outbound HTTP core. Every provider adapter issues upstream requests through a transport.Client, which owns the one retry loop (full-jitter backoff, Retry-After, per-provider attempt count), authentication decoration (Bearer, API-key headers, SigV4, OAuth, HMAC), error translation into apierror, and provider client spans. It replaces the ~8 copy-pasted retry loops that previously lived in each provider package.

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

func AddObserver

func AddObserver(hook AttemptHook)

AddObserver registers a process-lifetime observer invoked for every attempt on every Client. Intended to be called during startup (before serving); safe to call concurrently.

func ResetObservers

func ResetObservers()

ResetObservers removes all registered observers. Tests only.

Types

type AttemptHook

type AttemptHook func(AttemptInfo)

AttemptHook observes a single attempt. Hooks must not block; they feed health/latency accounting and span annotation.

type AttemptInfo

type AttemptInfo struct {
	Provider string // display name, e.g. "OpenAI"
	Slug     string // stable low-cardinality key, e.g. "openai" (matches config/registry)
	Attempt  int
	Method   string
	Path     string
	Status   int
	Err      error
	Latency  time.Duration
}

AttemptInfo describes one HTTP attempt for observers (the reliability manager and tracing). It is emitted once per attempt, including retries.

type AuthFunc

type AuthFunc func(req *http.Request, body []byte) error

AuthFunc decorates an outbound request with credentials. It receives the exact request body bytes so signing strategies (AWS SigV4, Volcengine HMAC) can hash the payload. It is invoked once per attempt on a freshly built request. A nil AuthFunc leaves the request unauthenticated (e.g. local Ollama).

func APIKeyHeaderAuth

func APIKeyHeaderAuth(header, key string) AuthFunc

APIKeyHeaderAuth returns an AuthFunc that sets a single API-key header, e.g. ("x-api-key", key) for Anthropic or ("xi-api-key", key) for ElevenLabs.

func BearerAuth

func BearerAuth(token string) AuthFunc

BearerAuth returns an AuthFunc that sets "Authorization: Bearer <token>".

type Client

type Client struct {
	// contains filtered or unexported fields
}

Client is a configured outbound HTTP client for one provider.

func New

func New(opts Options) *Client

New builds a Client.

func (*Client) BaseURL

func (c *Client) BaseURL() string

BaseURL returns the client's configured base URL (no trailing slash).

func (*Client) Do

func (c *Client) Do(ctx context.Context, r Request) (*http.Response, error)

Do runs the retry loop and returns the raw response. The caller owns and must close resp.Body. Do never returns a drained/closed response: a status- or transport-level retry that is interrupted mid-backoff returns an error.

func (*Client) HTTPClient

func (c *Client) HTTPClient() *http.Client

HTTPClient exposes the underlying *http.Client for the rare adapter that must issue a bespoke request (e.g. binary asset download) outside the retry loop.

func (*Client) JSON

func (c *Client) JSON(ctx context.Context, method, path string, in, out any, mods ...ReqOption) error

JSON marshals in (when non-nil) as the request body, executes the request, and decodes a success response into out (when non-nil). Non-2xx responses are converted through the provider's ErrorTranslator.

func (*Client) ProviderName

func (c *Client) ProviderName() string

ProviderName returns the display name used in error messages.

func (*Client) Raw

func (c *Client) Raw(ctx context.Context, method, path string, body io.Reader, contentType string, mods ...ReqOption) (*http.Response, error)

Raw executes a request with a caller-provided body reader (e.g. multipart) and returns the raw response. The caller owns and must close resp.Body.

func (*Client) Stream

func (c *Client) Stream(ctx context.Context, method, path string, in any, mods ...ReqOption) (*http.Response, error)

Stream marshals in (when non-nil) and returns the raw response for the caller to read (SSE or binary). The caller owns and must close resp.Body. Error statuses are translated and the body closed before returning.

type ErrorTranslator

type ErrorTranslator func(providerName string, status int, body []byte) *apierror.APIError

ErrorTranslator converts an upstream error response (status + body) into a canonical Polaris APIError. Each provider supplies one so its native error envelope is parsed while the resulting taxonomy stays uniform.

type Options

type Options struct {
	BaseURL         string
	ProviderName    string // display name used in error messages, e.g. "OpenAI"
	ProviderSlug    string // low-cardinality slug for provider spans, e.g. "openai"
	Auth            AuthFunc
	StaticHeaders   map[string]string
	Timeout         time.Duration
	Retry           RetryPolicy
	ErrorTranslator ErrorTranslator
	Hooks           []AttemptHook
	// HTTPClient overrides the constructed client (tests). When set, Timeout and
	// the provider-span RoundTripper are not applied.
	HTTPClient *http.Client
}

Options configures a Client.

type ReqOption

type ReqOption func(*Request)

ReqOption mutates a Request built by the JSON/Stream/Raw helpers.

func WithAccept

func WithAccept(accept string) ReqOption

WithAccept sets the Accept header.

func WithHeader

func WithHeader(key, value string) ReqOption

WithHeader sets one per-request header.

func WithHeaders

func WithHeaders(headers map[string]string) ReqOption

WithHeaders sets several per-request headers.

func WithQuery

func WithQuery(q url.Values) ReqOption

WithQuery sets the query string.

type Request

type Request struct {
	Method      string
	Path        string // relative to BaseURL, or an absolute URL
	Query       url.Values
	Body        []byte
	BodyReader  io.Reader
	ContentType string
	Accept      string
	Headers     map[string]string
}

Request is one logical outbound request. Body carries the canonical payload bytes so the retry loop can rebuild a fresh *http.Request each attempt; use BodyReader only for non-retryable streaming bodies (multipart uploads), which force a single attempt.

type RetryPolicy

type RetryPolicy struct {
	MaxAttempts       int
	InitialDelay      time.Duration
	MaxDelay          time.Duration
	RespectRetryAfter bool
}

RetryPolicy governs the transport's per-request retry loop. MaxAttempts is taken from each provider's configuration exactly as before (1 == no retry), so migrating a provider onto the transport never changes how many times it retries. The behavior improvements over the old per-provider loops are: full-jitter backoff, honoring Retry-After, and never returning a drained response when a backoff sleep is interrupted.

type SSEFrame

type SSEFrame struct {
	Event string
	Data  string
}

SSEFrame is one server-sent-events frame: an optional event name and the concatenated data payload.

type SSEReader

type SSEReader struct {
	// contains filtered or unexported fields
}

SSEReader parses a text/event-stream body into frames. It is modality-neutral: callers translate each frame's Data (JSON) into their own chunk types. It handles CRLF, multi-line data accumulation, `event:` names, comment lines (leading ':'), and a trailing frame with no terminating blank line, and guards against pathologically large frames.

func NewSSEReader

func NewSSEReader(r io.Reader) *SSEReader

NewSSEReader wraps r with the default max-frame guard (1 MiB).

func (*SSEReader) Next

func (s *SSEReader) Next() (SSEFrame, error)

Next returns the next frame, or io.EOF at end of stream.

type SSRFClient

type SSRFClient struct {
	// contains filtered or unexported fields
}

SSRFClient is an outbound HTTP client hardened against server-side request forgery: it enforces an allowed-scheme list, a denied-host list, and blocks private/reserved IPs at both URL-validation and dial time (so DNS rebinding cannot slip a public hostname onto an internal address). It is used to fetch caller-supplied file URLs.

func NewSSRFClient

func NewSSRFClient(cfg config.FileSSRFConfig, timeout time.Duration) *SSRFClient

NewSSRFClient builds an SSRFClient from the files SSRF configuration.

func (*SSRFClient) Do

func (c *SSRFClient) Do(req *http.Request) (*http.Response, error)

Do validates req.URL then executes it.

func (*SSRFClient) Get

func (c *SSRFClient) Get(ctx context.Context, rawURL string) (*http.Response, error)

Get validates rawURL then issues a GET.

func (*SSRFClient) ValidateURL

func (c *SSRFClient) ValidateURL(rawURL string) error

ValidateURL enforces the scheme allow-list, host deny-list, and literal-IP block.

Jump to

Keyboard shortcuts

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