middleware

package
v0.1.16 Latest Latest
Warning

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

Go to latest
Published: Aug 30, 2026 License: Apache-2.0 Imports: 5 Imported by: 0

Documentation

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

func CORS

func CORS(cfg CORSConfig) func(http.Handler) http.Handler

CORS returns a middleware that emits cross-origin headers for allowed origins and answers preflight OPTIONS requests directly. ALL per-request choices are precomputed here at boot (origin set, header strings) — the request path only does a map lookup and a few header writes, and a request WITHOUT an Origin header (every server-to-server / curl / mobile call) returns on the first line untouched, so non-browser traffic pays effectively nothing.

Placement: this MUST run BEFORE the tenant, response-cache, JWT and RBAC middlewares. (1) A preflight carries no credentials and no tenant, so it must be answered before JWT (which would 401 it) and before the tenant resolver (which could 400/500 a bare Host). (2) The response cache stores only status, body, Content-Type and ETag — never Access-Control-* — so a per-request Allow-Origin set by THIS outer middleware is never cached and replayed to a different origin.

func PermissiveCSP

func PermissiveCSP(next http.Handler) http.Handler

PermissiveCSP sets a CSP suitable for the GraphiQL IDE playground. GraphiQL loads scripts and styles from CDN, so it needs a relaxed policy. Apply only to /graphiql in development mode.

func Recoverer

func Recoverer(onPanic func(r *http.Request, recovered any, stack []byte)) func(http.Handler) http.Handler

Recoverer returns middleware that recovers a panic in any downstream handler or middleware and turns it into a clean JSON 500, so ONE request's panic never takes the process down. It is the request-chain half of the Phase-0 safety model (LIBRARY-HARDEN-S1) — the goroutine half is Ctx.SafeGo, because Go's recover() only reaches its OWN goroutine (a bare `go func(){panic()}()` in a handler crashes every tenant; this middleware cannot save that — SafeGo does).

onPanic (may be nil) is called with the request, the recovered value and the captured stack BEFORE the response is written — wire it to a metric counter and a structured log. It mirrors chi's Recoverer (no ResponseWriter wrapping, so the steady-state cost is a single deferred recover — identical to before) and re-panics on http.ErrAbortHandler so net/http can abort the connection.

func SecurityHeaders

func SecurityHeaders(next http.Handler) http.Handler

SecurityHeaders adds defensive HTTP response headers to every response. Register this as the outermost middleware in the chain.

func SelectiveCompress

func SelectiveCompress(skip func(r *http.Request) bool, level int, types ...string) func(http.Handler) http.Handler

SelectiveCompress is chi's Compress middleware with a per-request skip — the same shape as the response cache's path bypass (pkg/cache): most requests flow through the compressor, the skipped ones reach the next handler with the ResponseWriter UNWRAPPED.

Why it exists (FILES-BENCH finding, fixed in FILES-FIX-SENDFILE): chi's compressResponseWriter wraps EVERY response — even content types it never compresses — and does not implement io.ReaderFrom, so http.ServeContent's io.CopyN could not reach TCPConn.ReadFrom and file downloads fell back to a userspace copy loop instead of sendfile zero-copy (measured: 0 sendfile calls, 53% of nginx throughput at ~5.5× the CPU/byte). Skipping the wrapper on byte-serving routes restores the kernel fast path — and skipping compression on binary blobs is correct on its own terms (the FILES-V2 investigation: never compress images/video/binaries).

skip is consulted per request; everything else keeps the exact chimiddleware.Compress behavior (level + compressible content types).

func StrictCSP

func StrictCSP(next http.Handler) http.Handler

StrictCSP adds a restrictive Content-Security-Policy for API and GraphQL endpoints. Apply this to /api/* and /graphql — routes that serve JSON, never HTML.

Types

type CORSConfig

type CORSConfig struct {
	// AllowedOrigins is the exact origin allowlist (scheme + host + optional port,
	// e.g. "https://app.example.com"). The single literal "*" allows ANY origin.
	AllowedOrigins []string
	// AllowedMethods is echoed in the preflight Access-Control-Allow-Methods.
	// Empty ⇒ GET, POST, PUT, PATCH, DELETE, OPTIONS.
	AllowedMethods []string
	// AllowedHeaders is echoed in the preflight Access-Control-Allow-Headers.
	// Empty ⇒ Authorization, Content-Type.
	AllowedHeaders []string
	// ExposedHeaders lists response headers a browser script may read
	// (Access-Control-Expose-Headers). Empty ⇒ none beyond the CORS-safelisted set.
	ExposedHeaders []string
	// AllowCredentials, when true, sends Access-Control-Allow-Credentials: true so a
	// browser may send cookies / Authorization. Per the Fetch spec a credentialed
	// response may NOT use the literal "*" origin, so when AllowCredentials is set
	// and AllowedOrigins is "*", the request's Origin is REFLECTED instead.
	AllowCredentials bool
	// MaxAge bounds how long (seconds) a browser may cache a preflight result.
	// 0 ⇒ 600 (10 minutes). Negative ⇒ no Access-Control-Max-Age header.
	MaxAge int
}

CORSConfig configures cross-origin resource sharing for the browser-facing data-plane routes (/api, /auth, /graphql, /openapi). CORS is INFRASTRUCTURE configuration of the instance — which browser origins may call this engine — NOT part of the schema (the schema describes the data model, identical for every tenant; the allowed origins are a deployment decision). The zero value (no AllowedOrigins) disables CORS entirely: the engine emits no Access-Control-* header and short-circuits no preflight — the safe default. An operator opts in explicitly by listing origins (APPXIMO_CORS_ORIGINS), so a browser SPA on another origin never works by accident, only by configuration.

func (CORSConfig) Enabled

func (c CORSConfig) Enabled() bool

Enabled reports whether any origin is configured. A CORSConfig with no origins is a no-op and the engine does not wire the middleware at all.

Jump to

Keyboard shortcuts

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