middleware

package
v0.0.0-...-d1dd459 Latest Latest
Warning

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

Go to latest
Published: May 22, 2026 License: MIT Imports: 35 Imported by: 0

Documentation

Overview

Package middleware provides chi-compatible HTTP middleware for GoCell applications.

Each middleware follows the func(http.Handler) http.Handler signature and can be composed via standard chaining.

Available middleware:

  • RequestID: injects a unique X-Request-ID header
  • RealIP: extracts the client IP from X-Forwarded-For / X-Real-IP
  • Recovery: recovers from panics and returns 500
  • AccessLog: structured request/response logging via slog
  • SecurityHeaders: sets secure default HTTP headers
  • BodyLimit: enforces a maximum request body size
  • RateLimit: token-bucket rate limiting per client IP
  • CircuitBreaker: three-state circuit breaker for upstream protection
  • CSRF: validates request origin via Sec-Fetch-Site, Origin, and Referer headers
  • CookieSession: BFF cookie session with signed JWT encapsulation

BFF Middleware Ordering

For BFF (Browser-Facing) deployments with cookie-based sessions, the middleware chain order is critical:

	CSRF → CookieSession → AuthMiddleware → handler

  - CSRF runs first: rejects cross-origin requests (403) before any
    cookie processing or authentication happens. This prevents a
    malicious site from triggering cookie-based actions.
  - CookieSession runs second: reads the HttpOnly; Secure session cookie
    and injects an Authorization: Bearer header so that downstream
    middleware sees a standard JWT. SameSite defaults to Strict and remains
    configurable through CookieSessionConfig.
  - AuthMiddleware runs third: verifies the JWT (from cookie or header)
    and injects Claims into the request context.

Example:

csrfMW := middleware.CSRF(csrfCfg)
sessMW, err := middleware.NewCookieSession(sessCfg)
authMW := auth.AuthMiddleware(verifier, publicEndpoints)

rtr.Route("/api/v1", func(r cell.RouteMux) {
    protected := r.With(csrfMW, sessMW, authMW)
    protected.Handle("/resource", resourceHandler)
})

Package middleware provides chi-compatible HTTP middleware for the GoCell framework.

ref: go-kratos/kratos middleware/middleware.go — Middleware func(Handler) Handler chain pattern Adopted: standard func(http.Handler) http.Handler signature for chi compatibility.

route_pattern.go shares a request-scoped *patternRecorder between runtime/http/router (which writes the matched ServeMux pattern via RecordRoutePattern in the dispatch wrapper) and observability middleware (which reads it through RouteFor after next.ServeHTTP returns).

The recorder lives in this package — not in router/ — for two reasons:

  1. Tracing / AccessLog / Metrics already live here and read the value; keeping the accessor next to the readers avoids an import cycle that would otherwise force router → middleware → router.
  2. The mutable-container-via-context shape is local to the observability contract; router only owns the writer (the dispatch wrapper) and is free to evolve independently.

Recorder writes happen exactly once per request inside the router's patternRecordingMux; reads happen many times (one per observing middleware) but always after dispatch has returned, so no synchronization is required.

Short-circuit paths (auth reject, rate limit, circuit breaker, body limit, 405) complete before patternRecordingMux runs, so the recorder is still empty. The router injects a RouteResolver via WithRouteResolver so RouteFor can fall back to it and all three observability layers (Metrics, AccessLog, Tracing) see a consistent, non-"unmatched" label on those paths.

Index

Constants

View Source
const DefaultBodyLimit int64 = 1 << 20

DefaultBodyLimit is the default maximum request body size (1 MB).

View Source
const RuntimeCellIDSentinel = "_runtime"

RuntimeCellIDSentinel is the framework "owner" used as the cell label for requests that do not belong to any cell-owned HTTP namespace.

View Source
const UnmatchedRoute = "unmatched"

UnmatchedRoute is the sentinel route label used when a request does not match any registered route (e.g. 404). Using a fixed string prevents random paths from creating unbounded metric/span cardinality.

ref: slok/go-http-metrics — explicit handlerID pattern for 404 fallback

Variables

This section is empty.

Functions

func AccessLog

func AccessLog(clk clock.Clock) func(http.Handler) http.Handler

AccessLog returns an HTTP middleware that logs structured request/response information via slog.Info. A clock must be provided; use clock.Real() at the composition root. Fields: method, path, route, status, duration_ms, listener, cell_id, request_id, correlation_id, trace_id, real_ip. The listener field is emitted only when the router annotated the request with a non-empty physical listener name. When a service principal is present (Kind==PrincipalService), caller_cell is emitted. When a user principal is present (Kind==PrincipalUser), subject is emitted.

ref: go-zero rest/handler/loghandler.go — structured request logging with trace context

When a RecorderState exists in the context (created by the Recorder middleware), AccessLog reuses it. Otherwise it creates its own to remain usable as a standalone middleware.

func BodyLimit

func BodyLimit(maxBytes int64) func(http.Handler) http.Handler

BodyLimit restricts the request body to at most maxBytes bytes. If the body exceeds the limit, a 413 JSON error response is returned. Pass 0 or a negative value to use DefaultBodyLimit.

func CSRF

func CSRF(cfg CSRFConfig) func(http.Handler) http.Handler

CSRF returns middleware that validates request origin using Sec-Fetch-Site, Origin, and Referer headers. It provides defense-in-depth for APIs that may use bearer tokens (JWT) or cookie-based sessions.

func CellAttribution

func CellAttribution(resolve CellResolver) func(http.Handler) http.Handler

CellAttribution writes the owning cell ID into request context before protection middleware can short-circuit. Requests with no resolved cell keep an absent ctx key; Metrics converts absence to RuntimeCellIDSentinel.

func CircuitBreaker

func CircuitBreaker(cb Allower) (func(http.Handler) http.Handler, error)

CircuitBreaker returns HTTP middleware that protects upstream handlers using the given Allower. When the circuit is open, requests are rejected with 503 Service Unavailable. When closed or half-open, requests proceed to the next handler; the response status determines success/failure reporting (5xx = failure, everything else = success).

The done callback is invoked via defer to guarantee it is called even when the downstream handler panics.

The middleware reuses an existing RecorderState from context (created by the Recorder middleware). If none exists, it creates its own so it remains usable as a standalone middleware.

ref: sony/gobreaker — TwoStepCircuitBreaker for HTTP request protection ref: go-kit/kit circuitbreaker — middleware wrapping pattern

func ClearSessionCookie

func ClearSessionCookie(w http.ResponseWriter, cfg CookieSessionConfig)

ClearSessionCookie removes the session cookie by setting MaxAge=-1.

func CompilePublicEndpoints

func CompilePublicEndpoints(entries []string) (func(*http.Request) bool, error)

CompilePublicEndpoints parses a slice of "METHOD /path" entries and returns a per-request predicate that returns true when the request's (method, path) pair is in the public set.

Intended for Router.FinalizeAuth internals. Cells should not call this directly — declare public routes via auth.Mount with Public: true, and Router.FinalizeAuth compiles the aggregated entries at bootstrap time.

Returns a non-nil error aggregating all malformed or duplicate entries via errors.Join — the caller should treat any error as a startup failure.

Rules:

  • Entry format: "METHOD /path" (single space minimum; extra spaces trimmed).
  • Method is normalised to uppercase.
  • Path is normalised with path.Clean; must start with '/'.
  • Entries with no method prefix are rejected (fail-fast; no silent fallback).
  • Method must be one of: GET/HEAD/POST/PUT/PATCH/DELETE/OPTIONS/CONNECT/TRACE.
  • GET entries automatically also match HEAD (RFC 7231 §4.3.2).
  • Duplicate (method, path) pairs return an error (protect config cleanliness).
  • Empty entry slice is valid; the returned predicate always returns false.

ref: Go 1.22 net/http ServeMux pattern grammar "[METHOD] PATH" ref: otelhttp WithPublicEndpointFn per-request predicate

func DefaultProbeFilter

func DefaultProbeFilter(r *http.Request) bool

DefaultProbeFilter skips the canonical infra probe endpoints. Matched paths (exact): /healthz, /readyz, /livez, /metrics. Router.buildOuterMux applies it by default so high-frequency probe traffic does not emit spans.

func ListenerContext

func ListenerContext(name string) func(http.Handler) http.Handler

ListenerContext annotates every request with the physical listener name. Empty names are ignored so zero-ref test routers and standalone middleware do not emit a blank listener field.

func Metrics

func Metrics(collector metrics.Collector, clk clock.Clock) func(http.Handler) http.Handler

Metrics returns an HTTP middleware that records request count and duration using the provided Collector. A clock must be provided; use clock.Real() at the composition root.

When a RecorderState exists in the context (created by the Recorder middleware), Metrics reuses it. Otherwise it creates its own to remain usable as a standalone middleware.

Cell-label resolution reads kernel/ctxkeys.CellID from request context. Router-owned root attribution installs that key before short-circuiting protection middleware. Absence means framework/runtime traffic and records as RuntimeCellIDSentinel.

Route label resolution uses RouteFor, which reads the dispatch-time recorder first and then falls back to the RouteResolver injected by the router via WithRouteResolver. This means Metrics, AccessLog, and Tracing all see the same route label even on reject paths (auth, rate limit, circuit breaker, body limit, 405).

func NewCookieSession

func NewCookieSession(cfg CookieSessionConfig) (func(http.Handler) http.Handler, error)

NewCookieSession creates the cookie session middleware, returning an error if the configuration is invalid (e.g., Secret too short).

ref: labstack/echo — ToMiddleware() (MiddlewareFunc, error) pattern

func RateLimit

func RateLimit(limiter RateLimiter) func(http.Handler) http.Handler

RateLimit applies per-IP rate limiting using the provided RateLimiter. The client IP is obtained from the context (set by the RealIP middleware) or falls back to RemoteAddr. When the limit is exceeded, a 429 response with a dynamically computed Retry-After header is returned.

func RealIP

func RealIP(trustedProxies []string) func(http.Handler) http.Handler

RealIP extracts the client's real IP address. It only trusts the X-Forwarded-For and X-Real-Ip headers when the request's RemoteAddr is from a trusted proxy. If trustedProxies is empty or nil, no proxy is trusted and RemoteAddr is always used.

When proxies are trusted, X-Forwarded-For is scanned right-to-left to find the first IP that is NOT a trusted proxy. This prevents client-side header spoofing attacks.

ref: labstack/echo — ExtractIPFromXFFHeader right-to-left scanning ref: gin-gonic/gin — TrustedProxies CIDR list + reverse XFF scan

func RealIPFromChecker

func RealIPFromChecker(checker *proxyChecker) func(http.Handler) http.Handler

RealIPFromChecker creates the RealIP middleware using a pre-validated proxyChecker, avoiding redundant parsing when ValidateTrustedProxies has already constructed one.

func RecordRoutePattern

func RecordRoutePattern(ctx context.Context, pattern string)

RecordRoutePattern stores the matched ServeMux pattern in the recorder previously installed by WithRoutePatternRecorder. No-op if no recorder is present (e.g. unit tests that exercise a middleware without the router).

func Recorder

func Recorder(next http.Handler) http.Handler

Recorder creates a shared RecorderState and stores it in the request context so downstream middleware (AccessLog, Metrics, Recovery) can reuse it without redundant httpsnoop wrapping.

Place Recorder early in the middleware chain — before any middleware that needs to observe the final response status (e.g. AccessLog, Metrics) and before Recovery so that a panic-recovered 500 response is visible to all observers.

func Recovery

func Recovery(next http.Handler) http.Handler

Recovery catches panics in downstream handlers, logs the panic value and stack trace via slog.Error, and returns a 500 JSON error response. If the response has already been committed (WriteHeader called), Recovery only logs the panic and does not attempt to write an error response.

When a RecorderState exists in the context (created by the Recorder middleware), Recovery reuses it so upstream middleware (AccessLog, Metrics) can observe the 500 status. When used standalone without Recorder, Recovery creates its own RecorderState and stores it in the context, preserving committed-response detection.

func RequestID

func RequestID(next http.Handler) http.Handler

RequestID reads the request ID from the X-Request-Id header, or generates a new UUID v4 if absent. The ID is stored in the request context via ctxkeys.RequestID and bridged to ctxkeys.CorrelationID for cross-service tracing correlation. The ID is echoed back in the response header.

func RequestIDWithOptions

func RequestIDWithOptions(opts ...RequestIDOption) func(http.Handler) http.Handler

RequestIDWithOptions creates a RequestID middleware with configurable trust boundary options. The zero-value config preserves backward-compatible behavior (accepts client-supplied X-Request-Id when syntactically safe).

func RouteFor

func RouteFor(ctx context.Context, method, urlPath string) string

RouteFor returns the matched route pattern for the current request. It reads the dispatch-time recorder first, then falls back to the router-supplied RouteResolver (typically populated for short-circuit rejections that returned before patternRecordingMux ran). Returns UnmatchedRoute when neither source produces a non-empty pattern.

Tracing / AccessLog / Metrics share this single accessor so their route labels stay consistent on reject paths.

func SecurityHeaders

func SecurityHeaders(next http.Handler) http.Handler

SecurityHeaders sets security-related response headers on every request. This is a convenience wrapper around SecurityHeadersWithOptions with default configuration (HSTS max-age=63072000, no includeSubDomains, no preload).

func SecurityHeadersWithOptions

func SecurityHeadersWithOptions(opts ...SecurityHeadersOption) func(http.Handler) http.Handler

SecurityHeadersWithOptions creates a middleware that sets security-related response headers. The HSTS header is always emitted with at least max-age; includeSubDomains and preload require explicit opt-in via options.

Headers set:

  • X-Content-Type-Options: nosniff
  • X-Frame-Options: DENY
  • Strict-Transport-Security: max-age=<N>[; includeSubDomains][; preload]

func SetSessionCookie

func SetSessionCookie(w http.ResponseWriter, cfg CookieSessionConfig, jwt string) error

SetSessionCookie writes a signed (optionally encrypted) JWT cookie to the response. Returns an error if encoding fails or cookie exceeds browser size limit.

For better performance, use NewSessionCookieWriter to pre-build the SecureCookie instance instead of calling this function per-request.

func Tracing

func Tracing(tracer wrapper.Tracer, opts ...TracingOption) func(http.Handler) http.Handler

Tracing creates an HTTP middleware that starts a span for each request. The span is initially named "{method} {path}" and renamed to "{method} {routePattern}" after routing completes (if the span supports SpanRenamer). The http.route attribute carries the low-cardinality route pattern for OTel semantic conventions compliance.

Span status follows the otelhttp convention: 5xx responses mark the span as error with the status text as description; 4xx and below leave the span status unset (the status code attribute is always recorded).

ref: otelchi — extracts chi RoutePattern for span name after routing ref: otelhttp handler.go — span status set for 5xx, unset for 4xx ref: OTel semantic conventions — http.route must be low-cardinality template

When inbound headers carry tracing context, Tracing continues the upstream trace before span creation. W3C `traceparent` takes precedence and B3 is used only as a fallback. Invalid headers are ignored and result in a new root span.

For public-facing endpoints (determined by WithPublicEndpointFn), inbound trace context is NOT inherited. A new root trace is created and the remote context is recorded as linked attributes (linked.trace_id, linked.span_id).

When a RecorderState exists in the context (created by the Recorder middleware), Tracing reuses it. Otherwise it creates its own to capture http.status_code as a standalone middleware.

Single-span ownership (round-4): Tracing is the single HTTP request span owner. kernel/wrapper.HTTPHandler no longer creates an inner span — it writes contract id + contract-derived attributes (gocell.contract.id / kind / transport) into a shared AttrCarrier that Tracing installs in ctx before calling next.ServeHTTP; after next returns, Tracing late-binds the collected attributes onto its span. This means every contract-bound request produces exactly one server span annotated with both http.route and gocell.contract.* attributes — no duplicate counting in dashboards.

Probe bypass: when skipFn (via WithProbeFilter) returns true, Tracing skips span creation entirely. This replaces the earlier wrapper-level DefaultProbeFilter that never fired in practice because probe routes are registered on the outer mux and bypass wrapper.HTTPHandler entirely.

func ValidateTrustedProxies

func ValidateTrustedProxies(proxies []string) (*proxyChecker, error)

ValidateTrustedProxies validates all entries and returns the constructed proxyChecker for reuse. Returns a descriptive error for the first invalid entry. Used by router.MustNew() for fail-fast validation at construction time, eliminating the need to parse proxies twice (once to validate, once to use).

ref: gin-gonic/gin — SetTrustedProxies validates eagerly at config time

func WithRecorderState

func WithRecorderState(ctx context.Context, s *RecorderState) context.Context

WithRecorderState stores a RecorderState in the context.

func WithRoutePatternRecorder

func WithRoutePatternRecorder(ctx context.Context) context.Context

WithRoutePatternRecorder returns a copy of ctx carrying a fresh, empty recorder. Called once per request by the router root.

func WithRouteResolver

func WithRouteResolver(ctx context.Context, fn RouteResolver) context.Context

WithRouteResolver returns a copy of ctx carrying fn as the shared router-supplied route resolver. Called once per request by the router root before observability middleware runs.

Types

type Allower

type Allower interface {
	// Allow checks if the request should proceed.
	//
	// If the circuit is closed or half-open, Allow returns allowed=true and a
	// non-nil done callback that MUST be called exactly once with nil (success)
	// or a non-nil error (failure).
	//
	// If the circuit is open, Allow returns allowed=false and a nil done.
	Allow() (allowed bool, done func(err error))
}

Allower is the ISP-minimal interface required by the CircuitBreaker middleware. It covers only the "gate-and-report" concern of a two-step circuit breaker, decoupled from state inspection or statistics.

Callers that need state inspection (e.g. health checks) should depend on the concrete type or a richer interface defined in their own package.

ref: sony/gobreaker — TwoStepCircuitBreaker Allow/done(err) protocol ref: go-kratos/aegis — circuitbreaker.CircuitBreaker interface

type CSRFConfig

type CSRFConfig struct {
	// TrustedOrigins: allowed origins (scheme://host[:port]).
	// Supports wildcard subdomains: "https://*.example.com"
	//
	// Note: wildcards match ALL subdomain depths — "https://*.example.com"
	// matches both "https://sub.example.com" and "https://a.b.c.example.com".
	// For tighter control, list specific subdomains explicitly.
	TrustedOrigins []string

	// ExcludedPathPrefixes: URL path prefixes that bypass CSRF checks.
	// Paths are normalized with path.Clean before matching to prevent
	// traversal bypasses (e.g., /api/webhooks/../secret).
	ExcludedPathPrefixes []string

	// AllowSameSite controls behavior for Sec-Fetch-Site: same-site requests.
	// When true, same-site requests fall through to Origin/Referer validation
	// (not blindly allowed — still requires TrustedOrigins match).
	// When false, same-site requests are immediately rejected.
	// Default: false (secure default — same-site subdomain attacks blocked).
	AllowSameSite bool

	// AllowMissingOrigin controls behavior when no origin signal
	// (Sec-Fetch-Site, Origin, Referer) is present.
	// Default: false (fail-closed — all requests must carry origin info).
	// Set true only for API-only endpoints where non-browser clients
	// (cURL, server-to-server) are expected.
	AllowMissingOrigin bool
}

CSRFConfig configures the CSRF origin validation middleware.

func DefaultCSRFConfig

func DefaultCSRFConfig() CSRFConfig

DefaultCSRFConfig returns a CSRFConfig with secure defaults. Both AllowSameSite and AllowMissingOrigin default to false (fail-closed).

type CellResolver

type CellResolver func(method, path string) (string, bool)

CellResolver maps a concrete request to the owning cell ID.

type CircuitBreakerRetryAfter

type CircuitBreakerRetryAfter interface {
	// RetryAfter returns the suggested duration until the circuit may allow
	// requests again (typically the open-state timeout).
	RetryAfter() time.Duration
}

CircuitBreakerRetryAfter is an optional interface that Allower implementations can satisfy to provide Retry-After guidance on 503 responses. When implemented, the middleware sets the Retry-After header so clients know when to retry (RFC 7231 Section 7.1.3).

type ContractAttrsResolver

type ContractAttrsResolver func(method, path string) ([]wrapper.Attr, bool)

ContractAttrsResolver resolves contract-derived span attributes from a concrete request method/path. Routers use this to annotate spans when pre-handler middleware short-circuits before wrapper.HTTPHandler can append to the AttrCarrier.

type CookieSessionConfig

type CookieSessionConfig struct {
	// Secret is the HMAC key for SecureCookie signing (≥32 bytes, required).
	Secret []byte

	// EncryptKey is the AES key for cookie encryption.
	// nil = signing only, 16/24/32 bytes = AES-128/192/256-GCM.
	EncryptKey []byte

	// CookieName is the session cookie name. Default: "session".
	CookieName string

	// CookiePath is the cookie path. Default: "/".
	CookiePath string

	// CookieDomain is the cookie domain. Default: "" (current domain).
	CookieDomain string

	// CookieSameSite sets the SameSite attribute. Default: Strict.
	CookieSameSite http.SameSite

	// MaxAge is the cookie max age in seconds. Default: 900 (15min, matches JWT TTL).
	MaxAge int

	// Clock is used for cookie timestamp and expiry checks.
	// Required: must be set by the composition root (e.g. clock.Real() in
	// production, clockmock.New(...) in tests).
	Clock clock.Clock
}

CookieSessionConfig configures the BFF cookie session middleware.

func DefaultCookieSessionConfig

func DefaultCookieSessionConfig(secret []byte) CookieSessionConfig

DefaultCookieSessionConfig returns a CookieSessionConfig with safe defaults.

type RateLimiter

type RateLimiter interface {
	// Allow returns true if the request should proceed.
	Allow(key string) bool
}

RateLimiter decides whether a request identified by key should be allowed.

type RecorderState

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

RecorderState captures HTTP response metadata (status code, bytes written, committed state) without wrapping the ResponseWriter itself. This allows httpsnoop.Wrap to return a writer that preserves optional interfaces (http.Hijacker, http.Flusher, http.Pusher, io.ReaderFrom).

Multiple middleware can share a single RecorderState via context to avoid redundant httpsnoop wrapping. Use RecorderStateFrom to check for an existing state before creating a new one.

func NewRecorder

NewRecorder wraps w with httpsnoop hooks that capture response metadata into a RecorderState. The returned http.ResponseWriter preserves all optional interfaces (Hijacker, Flusher, Pusher, ReaderFrom) from the original writer.

1xx informational responses (100 Continue, 103 Early Hints) are forwarded but do not mark the response as committed.

func RecorderStateFrom

func RecorderStateFrom(ctx context.Context) *RecorderState

RecorderStateFrom retrieves a previously stored RecorderState from the context. Returns nil if none exists.

func (*RecorderState) BytesWritten

func (s *RecorderState) BytesWritten() int64

BytesWritten returns the total number of bytes written to the response body.

func (*RecorderState) Committed

func (s *RecorderState) Committed() bool

Committed reports whether WriteHeader (>= 200) or Write has been called. Informational 1xx responses do not mark the response as committed.

func (*RecorderState) Status

func (s *RecorderState) Status() int

Status returns the captured HTTP status code (default 200).

type RequestIDOption

type RequestIDOption func(*requestIDConfig)

RequestIDOption configures the RequestIDWithOptions middleware.

func WithReqIDPublicEndpointFn

func WithReqIDPublicEndpointFn(fn func(*http.Request) bool) RequestIDOption

WithReqIDPublicEndpointFn sets a per-request function that determines whether an endpoint is public-facing. For public endpoints, the client-supplied X-Request-Id header is ignored and a fresh UUID is always generated. This prevents untrusted callers from injecting arbitrary request IDs.

ref: go-chi/chi — warns to "only use this middleware if you can trust the headers" ref: otelhttp — WithPublicEndpointFn pattern for per-request trust decisions

type RouteResolver

type RouteResolver func(method, urlPath string) (pattern string, ok bool)

RouteResolver maps a concrete (method, urlPath) to a low-cardinality route pattern. Routers inject one via WithRouteResolver before the observability middleware chain runs so RouteFor can recover the pattern on requests rejected before dispatch (auth, rate limit, circuit breaker, body limit, 405). Returns ok=false when the request does not match any registered route.

func RouteResolverFrom

func RouteResolverFrom(ctx context.Context) RouteResolver

RouteResolverFrom retrieves the resolver installed by WithRouteResolver, or nil when none is registered (e.g. a middleware unit test that builds a chain without the router).

type SecurityHeadersOption

type SecurityHeadersOption func(*securityHeadersConfig)

SecurityHeadersOption configures the SecurityHeadersWithOptions middleware.

ref: unrolled/secure — STSIncludeSubdomains / STSPreload (affirmative opt-in) Adopted: affirmative logic consistent with GoCell's RequestIDOption / TracingOption pattern. Deviated from Echo's negative HSTSExcludeSubdomains to keep API intuitive.

func WithHSTSIncludeSubDomains

func WithHSTSIncludeSubDomains() SecurityHeadersOption

WithHSTSIncludeSubDomains appends the includeSubDomains directive to the Strict-Transport-Security header. Off by default — callers must explicitly opt in after verifying that all subdomains support HTTPS.

func WithHSTSMaxAge

func WithHSTSMaxAge(seconds int) SecurityHeadersOption

WithHSTSMaxAge overrides the default HSTS max-age (63072000 seconds / 2 years). Zero is valid per RFC 6797 (instructs browsers to remove HSTS). Negative values are clamped to zero.

func WithHSTSPreload

func WithHSTSPreload() SecurityHeadersOption

WithHSTSPreload appends the preload directive to the Strict-Transport-Security header. Off by default — callers must explicitly opt in after confirming eligibility at hstspreload.org.

type SessionCookieWriter

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

SessionCookieWriter writes and clears session cookies using a pre-built SecureCookie instance for consistent performance.

func NewSessionCookieWriter

func NewSessionCookieWriter(cfg CookieSessionConfig) (*SessionCookieWriter, error)

NewSessionCookieWriter creates a reusable writer for setting session cookies. Pre-builds the SecureCookie instance to avoid per-call reconstruction.

func (*SessionCookieWriter) Clear

Clear removes the session cookie by setting MaxAge=-1.

func (*SessionCookieWriter) Set

Set writes a signed (optionally encrypted) JWT cookie to the response. Returns an error if the encoded cookie exceeds the browser size limit (4096 bytes).

type TracingOption

type TracingOption func(*tracingConfig)

TracingOption configures the Tracing middleware.

func WithContractAttrsResolver

func WithContractAttrsResolver(fn ContractAttrsResolver) TracingOption

WithContractAttrsResolver installs a resolver that can provide contract attrs without waiting for the leaf wrapper.HTTPHandler. This keeps rate-limit/auth/body-limit short-circuits tagged with the same gocell.contract.* metadata as successful handler executions.

func WithProbeFilter

func WithProbeFilter(pred func(*http.Request) bool) TracingOption

WithProbeFilter installs a predicate that, when true for a given request, bypasses outer span creation entirely (the request is forwarded to next without a span). Use for health/readiness/liveness probe paths and other high-rate infra traffic where span volume is cost-prohibitive.

Combine with DefaultProbeFilter to skip the canonical probe endpoints (/healthz, /readyz, /livez, /metrics) that the Router registers directly on the outer mux.

ref: open-telemetry/opentelemetry-go-contrib otelhttp/config.go — Filter type.

func WithPublicEndpointFn

func WithPublicEndpointFn(fn func(*http.Request) bool) TracingOption

WithPublicEndpointFn sets a per-request function that determines whether an endpoint is public-facing (untrusted upstream). When it returns true, the middleware creates a new root trace instead of continuing the upstream trace. The remote span context is recorded as linked attributes for correlation.

ref: otelhttp WithPublicEndpointFn — new root + trace.Link to remote context

type WindowedRateLimiter

type WindowedRateLimiter interface {
	RateLimiter
	// Window returns the rate limit window duration and the maximum number
	// of requests allowed within that window.
	Window() (window time.Duration, limit int)
}

WindowedRateLimiter extends RateLimiter with window metadata for dynamic Retry-After calculation. Implementations that do not track windows can implement only RateLimiter; the middleware will fall back to a default.

Jump to

Keyboard shortcuts

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