http

package
v0.41.0 Latest Latest
Warning

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

Go to latest
Published: Jun 20, 2026 License: Apache-2.0 Imports: 23 Imported by: 0

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

Constants

This section is empty.

Variables

This section is empty.

Functions

func IsAuthSuppressed

func IsAuthSuppressed(ctx context.Context, clientName string) bool

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

func ParseRetryAfter(header string) time.Duration

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

func RetryAfterApplies(status int) bool

RetryAfterApplies reports whether Retry-After should be honored on the given response status. Per spec, only 429 and 503.

func WithAuthMarker

func WithAuthMarker(ctx context.Context, clientName string) context.Context

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

func WithOTelPropagate(ctx context.Context, propagate bool) context.Context

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

type AuthBackoff struct {
	InitialDelay time.Duration
	MaxDelay     time.Duration
	Factor       float64
}

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

type AuthResult struct {
	Value     string
	ExpiresIn time.Duration
}

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

type AuthSnapshot struct {
	HasCachedValue      bool
	ConsecutiveFailures int
	InFailedState       bool
}

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

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

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

type RedirectPolicy struct {
	Follow   bool
	Max      int
	KeepAuth bool
}

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.

Jump to

Keyboard shortcuts

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