Documentation
¶
Overview ¶
Package httpsemantics provides stdlib-only helpers for HTTP standards including OAuth token-response cache headers, RFC 6750 Bearer challenges, RFC 9110 conditional requests, RFC 8288 Link headers, and RFC 9110 Retry-After parsing/formatting.
These helpers are opt-in and framework-neutral. They do not change default behavior of any requestCore handler or responder.
Index ¶
- func ApplyBearerChallenge(h http.Header, c BearerChallenge)
- func ApplyBearerChallengeToParser(setHeader func(name, value string), c BearerChallenge)
- func ApplyTokenResponseNoStore(h http.Header)
- func ApplyTokenResponseNoStoreToParser(setHeader func(name, value string))
- func ClampRetryAfter(ra RetryAfter, now time.Time, maxDelay time.Duration) int
- func ExtractW3CTraceContext(parent context.Context, h http.Header) context.Context
- func ExtractW3CTraceContextFromMap(parent context.Context, headers map[string]string) context.Context
- func FormatBearerChallenge(c BearerChallenge) string
- func FormatETagList(tags []ETag) string
- func FormatLinkHeader(links []Link) string
- func FormatRetryAfter(ra RetryAfter, now time.Time, maxDelay time.Duration) string
- func FormatRetryAfterDate(t time.Time) string
- func FormatRetryAfterDelta(seconds int) string
- func InjectW3CTraceContext(ctx context.Context, h http.Header)
- func InjectW3CTraceContextToMap(ctx context.Context, headers map[string]string)
- func IsNoBodyStatus(status int) bool
- func ValidateErrorURI(uri string) error
- type BearerChallenge
- type BearerError
- type ETag
- type Link
- type PaginationConfig
- type PaginationLinks
- type PreconditionInput
- type PreconditionResult
- type RetryAfter
Constants ¶
This section is empty.
Variables ¶
This section is empty.
Functions ¶
func ApplyBearerChallenge ¶
func ApplyBearerChallenge(h http.Header, c BearerChallenge)
ApplyBearerChallenge sets the WWW-Authenticate header on an http.Header with the given Bearer challenge. The status code should be 401 (Unauthorized). The caller is responsible for determining that the response is a Bearer-protected resource-server 401; this helper does not automatically attach challenges to unrelated 401 responses.
func ApplyBearerChallengeToParser ¶
func ApplyBearerChallengeToParser(setHeader func(name, value string), c BearerChallenge)
ApplyBearerChallengeToParser sets the WWW-Authenticate header through a SetHeader function (e.g. webFramework.RequestParser.SetRespHeader). This is the v1 integration point for framework-neutral header setting.
func ApplyTokenResponseNoStore ¶
ApplyTokenResponseNoStore sets the headers required by RFC 6749 §5.1 for OAuth 2.0 access-token responses: Cache-Control: no-store and Pragma: no-cache. The caller is responsible for determining that the response is a token response; this helper only applies the headers.
RFC 6749 §5.1: "The authorization server MUST include the HTTP "Cache-Control" response header field [RFC2616] with a value of "no-store" in any successful response to the token endpoint. The authorization server MUST include the "Pragma" response header field [RFC2616] with a value of "no-cache" in any successful response to the token endpoint."
func ApplyTokenResponseNoStoreToParser ¶
func ApplyTokenResponseNoStoreToParser(setHeader func(name, value string))
ApplyTokenResponseNoStoreToParser sets the no-store headers through a SetHeader function (e.g. webFramework.RequestParser.SetRespHeader). This is the v1 integration point for framework-neutral header setting.
func ClampRetryAfter ¶
ClampRetryAfter caps a parsed Retry-After duration to a maximum delay. This prevents denial-of-service via excessively large Retry-After values. Returns the clamped duration in seconds.
func ExtractW3CTraceContext ¶
ExtractW3CTraceContext extracts W3C Trace Context headers (traceparent, tracestate) from the given HTTP request and returns a new context with the trace context embedded. This is the inbound extraction point for W3C trace propagation.
This helper uses the globally configured OpenTelemetry propagator (otel.GetTextMapPropagator()), which is typically a composite of propagation.TraceContext{} and propagation.Baggage{} as configured by libTracing.
Usage in framework adapters:
ctx := httpsemantics.ExtractW3CTraceContext(r.Context(), r.Header) // Pass ctx to request.NewContext or use it directly
func ExtractW3CTraceContextFromMap ¶
func ExtractW3CTraceContextFromMap(parent context.Context, headers map[string]string) context.Context
ExtractW3CTraceContextFromMap extracts W3C Trace Context headers from a map[string]string (e.g. framework parser header map) and returns a new context with the trace context embedded.
func FormatBearerChallenge ¶
func FormatBearerChallenge(c BearerChallenge) string
FormatBearerChallenge formats an RFC 6750 WWW-Authenticate Bearer challenge string. All parameter values are validated and escaped to prevent header injection. The realm is always included; other parameters are included only when non-empty.
The returned string is suitable for setting as the WWW-Authenticate response header value on a 401 response from a Bearer-protected resource server.
func FormatETagList ¶
FormatETagList formats a slice of ETags as a comma-separated header value.
func FormatLinkHeader ¶
FormatLinkHeader serializes a slice of Links as a single Link header value, with links separated by commas.
func FormatRetryAfter ¶
FormatRetryAfter formats a parsed RetryAfter as a header string, clamped to maxDelay seconds. If maxDelay is 0, no clamping is applied.
func FormatRetryAfterDate ¶
FormatRetryAfterDate formats a time.Time as an RFC 9110 Retry-After HTTP-date header string (RFC 7231 IMF-fixdate format).
func FormatRetryAfterDelta ¶
FormatRetryAfterDelta formats a delta-seconds value as an RFC 9110 Retry-After header string.
func InjectW3CTraceContext ¶
InjectW3CTraceContext injects the W3C Trace Context headers from the given context into the provided HTTP headers. This is the outbound injection point for W3C trace propagation when making downstream API calls.
Usage:
httpsemantics.InjectW3CTraceContext(ctx, req.Header) // Then send req via http.Client
func InjectW3CTraceContextToMap ¶
InjectW3CTraceContextToMap injects W3C Trace Context headers from the given context into a map[string]string.
func IsNoBodyStatus ¶
IsNoBodyStatus reports whether the given HTTP status code should not have a response body per RFC 9110.
func ValidateErrorURI ¶
ValidateErrorURI validates that the error_uri is a valid URI reference (absolute or relative). This prevents injection of malformed URIs into the WWW-Authenticate header.
Types ¶
type BearerChallenge ¶
type BearerChallenge struct {
// Realm is a description of the protected resource. If empty,
// "Protected" is used as a default.
Realm string
// Error is the RFC 6750 error code. If empty, no error parameter is
// included (used for initial 401 challenges without a specific error).
Error BearerError
// ErrorDescription is a human-readable description of the error.
// Must not contain characters that require escaping beyond standard
// quoted-string rules. If empty, the parameter is omitted.
ErrorDescription string
// ErrorURI is a URI identifying a human-readable page with
// information about the error. Must be a valid absolute or relative
// URI. If empty, the parameter is omitted.
ErrorURI string
// Scope is a space-delimited list of scopes that would suffice for
// the request. If empty, the parameter is omitted.
Scope string
}
BearerChallenge holds the parameters for an RFC 6750 WWW-Authenticate Bearer challenge. All fields are validated and escaped by FormatBearerChallenge before being included in the header value.
type BearerError ¶
type BearerError string
BearerError is a standard RFC 6750 Bearer challenge error code.
const ( // BearerErrorInvalidToken indicates the access token provided is // expired, revoked, malformed, or invalid for other reasons. BearerErrorInvalidToken BearerError = "invalid_token" // BearerErrorInvalidRequest indicates the request is missing a // required parameter, includes an unsupported parameter or // parameter value, repeats the same parameter, uses more than one // method for including an access token, or is otherwise malformed. BearerErrorInvalidRequest BearerError = "invalid_request" // BearerErrorInsufficientScope indicates that the access token // provided has insufficient scope for the resource being accessed. BearerErrorInsufficientScope BearerError = "insufficient_scope" // BearerErrorMissingToken indicates that no access token was // provided in the request. This is not a standard RFC 6750 error // code but is commonly used in WWW-Authenticate challenges to // distinguish "no token" from "invalid token". BearerErrorMissingToken BearerError = "missing_token" )
type ETag ¶
type ETag struct {
// Weak indicates whether this is a weak entity tag (W/ prefix).
Weak bool
// Value is the opaque entity-tag value without the surrounding
// double quotes or W/ prefix.
Value string
}
ETag represents an RFC 9110 entity tag with optional weak indicator.
func ParseETag ¶
ParseETag parses a single RFC 9110 entity-tag value. Supports both strong ("value") and weak (W/"value") forms. Returns an error for malformed input.
func ParseETagList ¶
ParseETagList parses a comma-separated list of entity tags from a header value (e.g. If-Match, If-None-Match). Returns the parsed ETags. The wildcard "*" is represented as ETag{Value: "*"}.
func (ETag) String ¶
String formats the ETag as an RFC 9110 entity-tag value: `W/"value"` for weak, `"value"` for strong.
func (ETag) StrongEqual ¶
StrongEqual reports whether two ETags are strongly equal per RFC 9110 §8.8.3.2: both must be strong and their values must match.
type Link ¶
type Link struct {
// URI is the link target. May be relative or absolute.
URI string
// Rel is the link relation type (e.g. "next", "prev", "self").
Rel string
// Title is an optional human-readable link title.
Title string
// Type is an optional media type hint for the target.
Type string
// HrefLang is an optional language hint.
HrefLang string
// ExtraParams holds additional parameters not covered by the
// fields above. Keys are parameter names, values are parameter
// values.
ExtraParams map[string]string
}
Link represents a single RFC 8288 Web Link with a target URI and optional parameters.
func BuildPaginationLinks ¶
func BuildPaginationLinks(cfg PaginationConfig) []Link
BuildPaginationLinks constructs RFC 8288 Link entries for a paginated collection. It preserves unrelated query parameters, omits unavailable relations (e.g. no "prev" on page 1), and safely handles relative or absolute request URLs.
func ParseLinkHeader ¶
ParseLinkHeader parses an RFC 8288 Link header value into a slice of Link entries. This is a simple parser for testing and verification.
type PaginationConfig ¶
type PaginationConfig struct {
// BaseURL is the request URL (absolute or relative) without query
// parameters. May include a path.
BaseURL string
// Page is the current page number (1-based).
Page int
// PageSize is the number of items per page.
PageSize int
// TotalItems is the total number of items across all pages.
// If 0, the "last" link is omitted.
TotalItems int
// PageParam is the query parameter name for the page number.
// Defaults to "page".
PageParam string
// PageSizeParam is the query parameter name for the page size.
// Defaults to "per_page".
PageSizeParam string
// Self is the URI for the "self" link relation. If empty, the
// "self" link is omitted.
Self string
// ExtraParams holds additional query parameters to preserve
// across pagination links.
ExtraParams url.Values
}
PaginationConfig holds the parameters for building pagination links.
type PaginationLinks ¶
PaginationLinks holds the rel types for a paginated collection.
type PreconditionInput ¶
type PreconditionInput struct {
// IfMatch is the value of the If-Match header. Empty if absent.
IfMatch string
// IfNoneMatch is the value of the If-None-Match header. Empty if absent.
IfNoneMatch string
// IfModifiedSince is the value of the If-Modified-Since header.
// Empty if absent.
IfModifiedSince string
// IfUnmodifiedSince is the value of the If-Unmodified-Since header.
// Empty if absent.
IfUnmodifiedSince string
// ResourceETag is the current entity tag of the resource.
// Empty if the resource has no ETag.
ResourceETag string
// ResourceModified is the last modification time of the resource.
// Zero if the resource has no Last-Modified.
ResourceModified time.Time
// IsSafeMethod is true for GET and HEAD (where If-None-Match can
// produce 304 rather than 412).
IsSafeMethod bool
}
PreconditionInput holds the request headers and resource state needed to evaluate RFC 9110 preconditions.
type PreconditionResult ¶
type PreconditionResult int
PreconditionResult indicates the outcome of precondition evaluation.
const ( // PreconditionProceed means the request should proceed normally. PreconditionProceed PreconditionResult = iota // PreconditionNotModified means the server should respond with 304 // Not Modified. PreconditionNotModified // PreconditionFailed means the server should respond with 412 // Precondition Failed. PreconditionFailed // PreconditionRequired means the server should respond with 428 // Precondition Required (the resource requires a precondition // that was not provided). PreconditionRequired )
func EvaluatePreconditions ¶
func EvaluatePreconditions(in PreconditionInput) PreconditionResult
EvaluatePreconditions evaluates RFC 9110 §13.1.2 precondition headers in precedence order and returns the appropriate result.
Precedence (RFC 9110 §13.2.2):
- If-Match
- If-Unmodified-Since
- If-None-Match
- If-Modified-Since
If-Match and If-Unmodified-Since produce 412 on failure. If-None-Match and If-Modified-Since produce 304 on failure for safe methods, 412 for unsafe methods.
type RetryAfter ¶
type RetryAfter struct {
// Delta is the delay in seconds. Valid only when IsDate is false.
Delta int
// Date is the retry time. Valid only when IsDate is true.
Date time.Time
// IsDate indicates whether the value is an HTTP-date form.
IsDate bool
}
RetryAfter represents a parsed RFC 9110 Retry-After header value. It is either a delta-seconds (non-negative integer) or an HTTP-date.
func ParseRetryAfter ¶
func ParseRetryAfter(s string) (RetryAfter, error)
ParseRetryAfter parses an RFC 9110 Retry-After header value. Supports both delta-seconds (integer) and HTTP-date (RFC 7231 IMF-fixdate) forms. Returns an error for malformed input.
func (RetryAfter) Duration ¶
func (r RetryAfter) Duration(now time.Time) time.Duration
Duration returns the effective delay duration. For delta-seconds, it returns Delta seconds. For HTTP-date, it returns the duration from now until the date (clamped to non-negative). The clock parameter allows injecting a time source for deterministic tests.