Documentation
¶
Overview ¶
Package http implements the `client "http"` block: a reusable HTTP client configuration that the http_* verb functions in package functions use to make outbound HTTP requests from action expressions.
Index ¶
- func IsAuthSuppressed(ctx context.Context, clientName string) bool
- func ParseRetryAfter(header string) time.Duration
- func RetryAfterApplies(status int) bool
- func WithAuthMarker(ctx context.Context, clientName string) context.Context
- func WithOTelPropagate(ctx context.Context, propagate bool) context.Context
- type AuthAttempt
- type AuthBackoff
- type AuthEvaluator
- type AuthHandler
- type AuthResult
- type AuthSnapshot
- type HTTPCallable
- type HTTPClient
- func (c *HTTPClient) AuthHandler() AuthHandler
- func (c *HTTPClient) BaseURL() *url.URL
- func (c *HTTPClient) CtyValue() cty.Value
- func (c *HTTPClient) DefaultHeaders() http.Header
- func (c *HTTPClient) DefaultRedirectPolicy() RedirectPolicy
- func (c *HTTPClient) DefaultRequestTimeout() time.Duration
- func (c *HTTPClient) DefaultRetryPolicy() RetryPolicy
- func (c *HTTPClient) Do(req *http.Request) (*http.Response, error)
- func (c *HTTPClient) DoWithRedirectPolicy(req *http.Request, pol RedirectPolicy) (*http.Response, error)
- func (c *HTTPClient) ParentEvalCtx() *hcl.EvalContext
- type RedirectPolicy
- type RetryPolicy
Constants ¶
This section is empty.
Variables ¶
This section is empty.
Functions ¶
func IsAuthSuppressed ¶
IsAuthSuppressed reports whether the given context is currently inside the auth hook for the named client. Verb functions check this before evaluating the auth hook for a request — if true, the request is sent with no Authorization header (or with whatever opts.auth supplies).
func ParseRetryAfter ¶
ParseRetryAfter parses an HTTP Retry-After header value. Both the delta-seconds and HTTP-date forms are honored. Returns 0 if the value is empty, malformed, or in the past.
func RetryAfterApplies ¶
RetryAfterApplies reports whether Retry-After should be honored on the given response status. Per spec, only 429 and 503.
func WithAuthMarker ¶
WithAuthMarker returns a derived context that adds clientName to the reentrancy marker set. The set is treated as immutable: the returned context carries a fresh map containing all previously-marked names plus clientName, so concurrent goroutines reading the parent context never observe a half-mutated set.
func WithOTelPropagate ¶
WithOTelPropagate returns a derived context that overrides the client's default propagation setting for one request. Pass false to suppress; pass true to force on (rare — usually the client default already enables it).
The verb function uses this to thread per-call opts.otel.propagate through to the conditional propagator without rebuilding the transport stack.
Types ¶
type AuthAttempt ¶
type AuthAttempt struct {
// Reason is "initial" (first call, or after TTL expiry) or
// "unauthorized" (after a 401 response).
Reason string
// Failures is the number of consecutive prior failures of this hook.
Failures int
// PreviousStatus is the HTTP status of the response that triggered
// this re-evaluation. 0 on the initial call.
PreviousStatus int
}
AuthAttempt is the structured value exposed to an auth expression as `ctx.auth_attempt`. It describes why the hook is running, so a sophisticated hook can treat the first attempt differently from a re-auth.
type AuthBackoff ¶
AuthBackoff describes the exponential backoff applied after the auth hook has accumulated `MaxFailures` consecutive failures.
type AuthEvaluator ¶
type AuthEvaluator func(attempt AuthAttempt) (AuthResult, error)
AuthEvaluator is the function the verb function passes to AuthHandler.Get to actually evaluate the auth expression. The closure captures the HCL expression and config; the cache calls it under the singleflight mutex when a fresh value is needed.
type AuthHandler ¶
type AuthHandler interface {
// ClientName returns the name of the client this handler belongs
// to. Used by verb functions to manage the reentrancy marker.
ClientName() string
// Expression returns the HCL expression that should be evaluated to
// produce the Authorization header value. The verb function uses it
// to build the AuthEvaluator closure.
Expression() hcl.Expression
// Get returns a cached or freshly-evaluated Authorization header.
//
// If reentrancy suppression applies (the client's name is in the
// marker set on ctx), Get returns ("", nil) — the verb function
// must send the request with no Authorization header.
//
// If the cache holds a value that has not expired, Get returns it
// without calling eval.
//
// If the cache is empty or expired, Get calls eval under a
// singleflight mutex (concurrent callers wait on the same
// evaluation). The reason argument seeds AuthAttempt.Reason; pass
// "initial" for the normal first-time / TTL-expired case and
// "unauthorized" for a re-eval after a 401.
//
// If the handler is in failed state (consecutive failures exceeded
// MaxFailures and the backoff has not yet elapsed), Get returns an
// error without calling eval.
Get(ctx context.Context, reason string, previousStatus int, eval AuthEvaluator) (string, error)
// Invalidate marks the cached value as stale. The next call to Get
// will re-evaluate. Used after a 401 response to force a fresh
// credential on the next attempt.
Invalidate()
// RecordResult updates the consecutive-failure counter based on the
// status of a request that consumed the handler's value:
// - 401 → failure (eligible for failed-state entry)
// - any other status → success, counter reset
//
// Note: 401 caused by a hook *evaluation* error is recorded
// internally by Get itself — RecordResult is for wire results.
RecordResult(status int)
// Snapshot returns a copy of the handler's internal counters for
// observability and tests. Implementations should make this safe to
// call concurrently with other methods.
Snapshot() AuthSnapshot
}
AuthHandler is the per-client interface the verb functions use to fetch and update Authorization header state. Real HTTPClients return an *authCache; mock clients are free to provide any implementation.
type AuthResult ¶
AuthResult is the parsed return value of an auth expression. The Value field is the literal Authorization header to send. ExpiresIn, if non-zero, gives the lifetime of the credential after which the cache should be considered stale and the hook re-run on the next request.
func ParseAuthResult ¶
func ParseAuthResult(val cty.Value) (AuthResult, error)
ParseAuthResult interprets the value returned by the auth expression. Accepted forms:
- string → AuthResult{Value: s}
- object {value, expires_in?, expires_at?, refresh_early?} → parsed
expires_in and expires_at are mutually exclusive. refresh_early is subtracted from the computed expiry to refresh proactively. The result's ExpiresIn field is the time *from now* at which the credential should be considered stale, or 0 if no TTL was provided.
type AuthSnapshot ¶
AuthSnapshot is a read-only view of an AuthHandler's internal state.
type HTTPCallable ¶
type HTTPCallable interface {
GetName() string
BaseURL() *url.URL
DefaultHeaders() http.Header
DefaultRequestTimeout() time.Duration
DefaultRedirectPolicy() RedirectPolicy
DefaultRetryPolicy() RetryPolicy
// AuthHandler returns the auth cache and configuration for this
// client, or nil if no `auth` expression was configured. Mock
// implementations may return nil to opt out of auth entirely.
AuthHandler() AuthHandler
// ParentEvalCtx returns the HCL evaluation context the client was
// registered against, or nil for synthetic clients (e.g. mocks, the
// shared null client). Verb functions need it to evaluate lazy
// expressions like retry.on_response that were stored at config time.
ParentEvalCtx() *hcl.EvalContext
// Do sends a request using the implementation's default redirect policy.
Do(req *http.Request) (*http.Response, error)
// DoWithRedirectPolicy sends a request using the supplied per-call
// redirect policy in place of the default. Mock implementations that do
// not actually follow redirects may delegate to Do(req).
DoWithRedirectPolicy(req *http.Request, pol RedirectPolicy) (*http.Response, error)
}
HTTPCallable is the interface the verb functions require of any value passed as the client argument. The real HTTPClient implements it; mock client types may also implement it to participate in the same call path. The verb functions never type-assert to a concrete type — they go through this interface exclusively, which keeps mock clients transparent to the verb function code path.
func GetHTTPCallableFromValue ¶
func GetHTTPCallableFromValue(val cty.Value) (HTTPCallable, error)
GetHTTPClientFromCapsule extracts an *HTTPClient (or anything implementing the HTTPCallable interface, since this is structural) from a cty value. It accepts:
- a plain client capsule wrapping an *HTTPClient (via CtyValue())
- any other capsule whose encapsulated value satisfies HTTPCallable
- an object with a _capsule attribute containing either of the above
Returns a nil HTTPCallable if the value is null; callers should treat that as the default-client path.
type HTTPClient ¶
type HTTPClient struct {
cfg.BaseClient
// contains filtered or unexported fields
}
HTTPClient is the runtime representation of a `client "http"` block. It implements config.Client, config.CtyValuer, and HTTPCallable (the interface the verb functions consume).
func NullClient ¶
func NullClient() *HTTPClient
NullClient returns a zero-configured HTTPClient equivalent to passing `null` as the client argument to an http_* verb function:
- no default headers
- no auth, no cookies, no retries
- follow redirects (up to 10)
- TLS with system roots, full verification
- 30-second whole-request timeout
- OTel propagation on
The returned client is safe for concurrent use and may be shared.
func (*HTTPClient) AuthHandler ¶
func (c *HTTPClient) AuthHandler() AuthHandler
AuthHandler returns the auth cache for this client, or nil if no `auth` expression was configured. Verb functions use it to fetch the Authorization header for outbound requests and to record per-request status for failure tracking.
func (*HTTPClient) BaseURL ¶
func (c *HTTPClient) BaseURL() *url.URL
BaseURL returns the client's configured base URL, or nil if none.
func (*HTTPClient) CtyValue ¶
func (c *HTTPClient) CtyValue() cty.Value
CtyValue exposes the client as a generic client capsule. There is no nested object structure for HTTP clients, unlike bus-backed clients.
func (*HTTPClient) DefaultHeaders ¶
func (c *HTTPClient) DefaultHeaders() http.Header
DefaultHeaders returns the default headers configured on the client. The returned http.Header should be treated as read-only by callers — they must clone it before mutating.
func (*HTTPClient) DefaultRedirectPolicy ¶
func (c *HTTPClient) DefaultRedirectPolicy() RedirectPolicy
DefaultRedirectPolicy returns the redirect policy this client was configured with. Verb functions use it as the base for per-call overrides.
func (*HTTPClient) DefaultRequestTimeout ¶
func (c *HTTPClient) DefaultRequestTimeout() time.Duration
DefaultRequestTimeout returns the client's whole-request timeout, or 0 if none was configured.
func (*HTTPClient) DefaultRetryPolicy ¶
func (c *HTTPClient) DefaultRetryPolicy() RetryPolicy
DefaultRetryPolicy returns the retry policy this client was configured with. Clients without a `retry { ... }` block return a no-retry policy (MaxAttempts == 1).
func (*HTTPClient) Do ¶
Do sends a request through this client's transport stack using the client's configured redirect policy. The returned response's Body must be closed by the caller.
func (*HTTPClient) DoWithRedirectPolicy ¶
func (c *HTTPClient) DoWithRedirectPolicy(req *http.Request, pol RedirectPolicy) (*http.Response, error)
DoWithRedirectPolicy sends a request using a per-call redirect policy in place of the client's default. It constructs a fresh *http.Client that reuses the underlying Transport (and thus the connection pool) and the shared cookie jar, but installs a CheckRedirect closure built from pol. This is necessary because *http.Client exposes a single CheckRedirect hook that closes over its values at construction time.
func (*HTTPClient) ParentEvalCtx ¶
func (c *HTTPClient) ParentEvalCtx() *hcl.EvalContext
ParentEvalCtx returns the HCL evaluation context the client was registered against, or nil for synthetic clients (e.g. NullClient). Used by verb functions to evaluate lazy expressions like retry.on_response.
type RedirectPolicy ¶
RedirectPolicy controls redirect-following behavior. It is normally taken from the HTTPClient's configuration; verb functions may construct a modified policy and pass it to DoWithRedirectPolicy for a single call.
type RetryPolicy ¶
type RetryPolicy struct {
MaxAttempts int
InitialDelay time.Duration
MaxDelay time.Duration
BackoffFactor float64
Jitter bool
RetryOn map[int]struct{}
RespectRetryAfter bool
AllowNonIdempotent bool
// OnResponse is an HCL expression evaluated by the verb function
// after each attempt that returned a response. nil means no hook
// is configured. The expression has access to ctx.response (the
// in-flight response) and ctx.attempt (1-indexed) and may return
// null/false (stop), true (retry with normal backoff), or a
// number/duration (wait that long, then retry).
OnResponse hcl.Expression
}
RetryPolicy describes how to retry failed HTTP requests.
MaxAttempts == 1 means no retry: the initial attempt is performed and the result is returned regardless of outcome. This is the default for clients that did not configure a `retry { ... }` block.
func ParseRetryPolicyFromValue ¶
func ParseRetryPolicyFromValue(val cty.Value) (RetryPolicy, error)
ParseRetryPolicyFromValue parses a per-call opts.retry override from a cty value. Unlike parseRetryBlock, this version accepts an already- evaluated object (because opts.retry is an inline literal in an action expression, not a sub-block of a client definition).
The on_response field is intentionally not supported in per-call overrides: HCL has already evaluated the object by the time we see it, so a hook expression would be reduced to whatever value the (then-empty) response context produced — useless. Per-call retry overrides are for counts, delays, and status sets; complex hooks belong on the client.
func (RetryPolicy) Delay ¶
func (p RetryPolicy) Delay(attempt int) time.Duration
Delay computes the wait duration before performing the given attempt number (1-indexed). Attempt 1 has zero delay (it's the initial request); attempt N >= 2 has delay InitialDelay * BackoffFactor^(N-2), capped at MaxDelay, with full jitter applied if Jitter is true.
func (RetryPolicy) MethodRetryable ¶
func (p RetryPolicy) MethodRetryable(method string) bool
MethodRetryable returns true if the given HTTP method is allowed to retry under this policy. Idempotent methods (GET, HEAD, OPTIONS, PUT, DELETE) are always retryable; POST, PATCH, and any other method only when AllowNonIdempotent is set.
func (RetryPolicy) ShouldRetryStatus ¶
func (p RetryPolicy) ShouldRetryStatus(status int) bool
ShouldRetryStatus returns true if a response with this status code matches the policy's RetryOn set.