Documentation
¶
Overview ¶
Package config loads a Cadishfile from disk and turns each site block into a runtime *Site that the server can execute: a compiled *pipeline.Pipeline, a *cache.Store built from the site's `cache { … }` block, and the site's origin.Origin composed from its `upstream`/`origin chain` directives.
It is the bridge between the semantics-free AST (internal/cadishfile), the pure evaluation engine (internal/pipeline), the cache store (internal/cache) and the origin layer (internal/origin). The server (internal/server) consumes the resulting *Config and never touches the raw AST.
Load performs the import splice + env substitution + Compile sequence once, at startup, and surfaces every error with its source position (file:line:col) so a bad config fails fast and legibly.
Index ¶
- func AdminExposureWarning(addr string) string
- func DiskBudgetFromNodes(nodes []cadishfile.Node) (int64, bool)
- func InjectedResolverForTest() lb.EndpointResolver
- func ParseDuration(s string) (time.Duration, error)
- func ParseSize(s string) (int64, error)
- func ParseUpstreamURL(tok string, pos cadishfile.Pos) error
- func SwapK8sClientFactoryForTest() (captured *[]string, restore func())
- func UpstreamCarriesPoolHealth(d *cadishfile.Directive) bool
- func ValidateListenAddr(s string) error
- func ValidateStructure(name, src, baseDir string) error
- func ValidateStructureFile(path string) error
- func ValidateStructureSandboxed(name, src string) error
- type AdminConfig
- type CacheBudgetChange
- type Config
- func (c *Config) CacheBudgetChanges(old *Config) []CacheBudgetChange
- func (c *Config) Close() error
- func (c *Config) CloseExcept(keep map[*cache.Store]bool) error
- func (c *Config) ClusterListenAddrs() []string
- func (c *Config) ClusterRegions() map[string]struct{}
- func (c *Config) Clusters() []*cluster.Membership
- func (c *Config) Pools() []*lb.Upstream
- func (c *Config) Start(ctx context.Context) error
- func (c *Config) StartShared(ctx context.Context) error
- func (c *Config) TotalRAMCacheBytes() int64
- func (c *Config) TransplantPoolsFrom(old *Config)
- func (c *Config) TransplantStoresFrom(old *Config)
- type LoadOptions
- type ProxyProtocolConfig
- type SecurityConfig
- type ServerConfig
- type Site
Constants ¶
This section is empty.
Variables ¶
This section is empty.
Functions ¶
func AdminExposureWarning ¶
AdminExposureWarning returns a human-readable warning when an admin listen address binds beyond loopback, or "" when the bind is loopback-only. The admin API is served over plain HTTP and gated only by a bearer token, so exposing it past loopback — a wildcard bind (`:9090`, `0.0.0.0`, `::`) or any routable IP / hostname — sends that token across the network in cleartext. Exposing admin is a supported deployment (behind your own TLS terminator / network controls), so this is a startup WARNING, not a hard error. A malformed address is left to ValidateListenAddr; this helper stays silent on it.
func DiskBudgetFromNodes ¶ added in v0.2.3
func DiskBudgetFromNodes(nodes []cadishfile.Node) (int64, bool)
DiskBudgetFromNodes returns the effective disk-tier budget a body scope would build: the SIZE of the last parseable `disk PATH SIZE` inside any `cache { … }` block in nodes (last wins, matching parseCacheBlock / buildStore), or 0 when no disk line configures one. The second result reports whether a `disk` directive with a valid size was seen (false ⇒ the returned 0 is the default, not an explicit `disk PATH 0`).
Unlike parseCacheBlock (the strict, *Site-taking build path that hard-errors on the FIRST malformed entry), this is TOLERANT: it skips `disk` lines that are missing a size or carry an unparseable one, so a check pass can compute the same "is the budget 0?" notion buildStore uses over a raw []Node — including the global scope — without aborting on entries that are reported separately (e.g. as invalid-size). It is the shared source of truth for that budget so the check path can never drift from the runtime.
func InjectedResolverForTest ¶ added in v0.2.1
func InjectedResolverForTest() lb.EndpointResolver
InjectedResolverForTest returns a do-nothing lb.EndpointResolver suitable for LoadOptions.EndpointResolver — the ingress/gateway path injects an already-built resolver so the config builds NO config-owned k8s client. Cross-package test seam.
func ParseDuration ¶
ParseDuration parses a cadish duration literal as used by every duration-valued directive (`cache_ttl … ttl/grace/hit_for_miss`, `health … interval`, `timeout connect/first_byte/between_bytes`, `sign cloudfront … ttl`). It delegates to pipeline.ParseDuration — the single source of truth for duration syntax — which extends Go's time.ParseDuration with day ("d") and week ("w") units (e.g. "60s", "24h", "365d"). Exported so `cadish check` can validate these values at LINT time, with a file:line, by reusing the same parser the runtime uses rather than reimplementing it.
func ParseSize ¶
ParseSize parses a byte-size literal as used in `cache { ram 2GiB; disk … 2TiB }`. It accepts an optional suffix: binary (KiB/MiB/GiB/TiB/PiB, powers of 1024) or decimal (KB/MB/GB/TB/PB, powers of 1000), or a bare "B"/no suffix for bytes. The number may be fractional (e.g. "1.5GiB"). Parsing is case-insensitive.
func ParseUpstreamURL ¶
func ParseUpstreamURL(tok string, pos cadishfile.Pos) error
ParseUpstreamURL validates one `to …` backend target — the URL/scheme/host:port the load balancer dials. It delegates to lb.ParseTarget, the single source of truth for backend-target syntax (http/https static, dns/k8s dynamic, or a bare host:port ⇒ http), so a target that loads at runtime also lints clean.
Exported so `cadish check` can reject a bogus `to ht!tp://[::bad`, an empty target, or an unsupported scheme at LINT time with a file:line, instead of leaving it to config load. The returned error is a positioned *cadishfile.ParseError carrying pos.
func SwapK8sClientFactoryForTest ¶ added in v0.2.1
func SwapK8sClientFactoryForTest() (captured *[]string, restore func())
SwapK8sClientFactoryForTest installs a recording k8s client factory that captures the Kubeconfig string of every k8s.Options it is asked to build a client with, in order. It returns a pointer to the captured slice and a restore func. Cross-package test seam (the server's reload test asserts the kubeconfig survives a SIGHUP recompile); production code never calls it. The fake clients it hands back resolve to zero endpoints and never fail their cache sync, so a k8s:// config compiles + starts offline.
func UpstreamCarriesPoolHealth ¶ added in v0.2.1
func UpstreamCarriesPoolHealth(d *cadishfile.Directive) bool
UpstreamCarriesPoolHealth reports whether the `upstream`/`cluster` block d builds as an lb.Upstream POOL — the only origin kind whose backend liveness the `upstream_healthy` matcher can actively track (a health FSM driven by an active `health { … }` probe or passive ejection). A named `cluster NAME { … }` pool always qualifies; an `upstream` qualifies UNLESS it is a trivial single-backend httporigin (no lb features) or an S3 (`bucket`)/CloudFront (`sign`) origin — none of which carry a health FSM. Exported so `cadish check` can warn (detectUpstreamHealthyNonPool) when `upstream_healthy NAME` references a name that resolves "assumed healthy" (the R03 footgun) instead of a really-probed pool. It mirrors buildOne's own dispatch (scanUpstreamFlags + isTrivialUpstream), the single source of truth, so check and run can never disagree on what becomes a pool. A nameless membership `cluster { … }` block is not a pool target and returns false.
func ValidateListenAddr ¶
ValidateListenAddr checks that s is a usable bind address — "host:port", ":port", or "ip:port". A botched IP literal (e.g. "0.0.0.0.1") is rejected HERE, with a config position, instead of silently passing config load and only failing at net.Listen bind time. Hostnames are accepted (resolved at bind); only an IP-SHAPED host that fails to parse is an error, so "localhost" / "db" pass while "0.0.0.0.1" does not.
func ValidateStructure ¶
ValidateStructure performs the STRUCTURAL build validation that config.Load (the `cadish run` build path) does, but WITHOUT any network/DNS/bind/store side effects. It is the pre-flight gate behind `cadish check`: a config that ValidateStructure accepts will not fail config.Load at config-build time.
It mirrors config.Load up to (and including) the per-site origin-layer wiring:
- parse + env substitute + group expansion,
- per-site import splice (the same FileImportResolver run uses),
- pipeline.Compile (pure),
- the origin-layer STRUCTURE: every site needs an upstream, upstream/cluster names are unique, each pool's lb config parses + validates (e.g. a malformed `sticky` line), and an `origin chain` only references declared upstreams.
It deliberately does NOT construct origins (no lb.Upstream → no DNS resolve, no s3/cfsign client, no k8s API client), open cache stores, create temp dirs, or probe geo databases — those are either real I/O or handled by check's own value validators. The goal is the invariant: `cadish check` exits 0 ⇒ `cadish run` will not fail at config-build time.
name is the diagnostic source name; baseDir is the directory imports resolve against (matching loadFromSource). The first structural problem is returned as a positioned error ("file:line:col: msg"), identical to what config.Load would surface, so check prints the same diagnostic run would.
func ValidateStructureFile ¶
ValidateStructureFile is ValidateStructure for a file on disk: it reads the file and resolves imports/relative paths against the file's own directory, matching config.Load.
func ValidateStructureSandboxed ¶
ValidateStructureSandboxed is the sandboxed variant for the admin playground: it performs NO filesystem access. Import directives splice to nothing (the playground submits self-contained buffers and blocks imports), so a site's own body is validated as-is. Like ValidateStructure it has no network/DNS/bind side effects.
Types ¶
type AdminConfig ¶
type AdminConfig struct {
// Listen is the admin server bind address (e.g. ":9090", "127.0.0.1:9090").
Listen string
// AuthToken is the bearer token required on every admin request. Mandatory:
// an admin block without one is a config error (an unauthenticated admin
// surface would leak the config and live metrics).
AuthToken string
// Metrics enables the Prometheus text-format `/metrics` endpoint when true
// (the JSON API + dashboard are always served; this is the extra scrape
// endpoint). Off unless the bare `metrics` flag is present.
Metrics bool
}
AdminConfig is the parsed `admin { … }` global block: the opt-in observability / dashboard surface. It is NIL when no admin block is present (the common case), in which case no admin listener is started and the datapath metrics seam stays nil (zero cost).
type CacheBudgetChange ¶ added in v0.2.1
type CacheBudgetChange struct {
Host string // the surviving site's primary host
Details []string // per-field diffs, e.g. "ram 67108864B->134217728B", `disk_path "/a"->"/b"`
}
CacheBudgetChange describes one surviving site whose NEW cache budget or disk path differs from the warm store carried across a reload. cache.Store has NO live resize, so the change is silently a no-op until a full restart: the OLD store (old RAM/disk budget, old path) keeps serving. The reload path surfaces this as a WARNING so an operator who "resized the cache" and reloaded is not misled into thinking it applied.
type Config ¶
type Config struct {
// Sites are the runtime sites in source order.
Sites []*Site
// TLS is the per-site TLS configuration (hostnames + tls directive), in site
// order, for building the server's tlsacme.Manager. The server decides whether
// to bind :443 from these.
TLS []tlsacme.SiteConfig
// Admin is the parsed `admin { … }` global block, or NIL when no admin block
// is present (the common case). When set, cadish starts the opt-in
// observability/dashboard server on its own listener (internal/admin) and
// threads a metrics seam through the datapath; when nil, none of that exists
// and the datapath pays nothing. The Cadishfile path is recorded so the admin
// `cadish check`-style config view can re-read it.
Admin *AdminConfig
ConfigPath string
// Security is the parsed global `security { … }` block (WAF v1c, D52), or NIL
// when absent (the common case). It carries cross-cutting security observability
// for v1 — the audit-log target — which is OFF by default. The native security
// primitives (allow/deny/rate_limit) are site-level and not gated by this block.
Security *SecurityConfig
// StrictHost is the global `strict_host` option: when true the server rejects a
// request whose Host matches no declared site address with 421 Misdirected
// Request, instead of the lenient single-site fallback (serve ANY Host from the
// only configured site). Default false = lenient (backward-compatible). It hardens
// a single-site deployment against cache-poisoning / Host-confusion by an
// undeclared Host. The server reads it once at routing-build time.
StrictHost bool
// AccessLogOff is the global `access_log off` option: when true the server's
// in-memory access-log fan-out hub (D44) is disabled, so even an attached
// `cadish logs` consumer receives nothing and the hot path's only cost is the
// idle atomic check. Default false = hub on (but idle-free until a consumer
// attaches). The `-access-log off` run flag is OR'd with this.
AccessLogOff bool
// ProxyProtocol is the parsed global `proxy_protocol { … }` block (the opt-in
// PROXY-protocol listener), or NIL when absent (the common case). When set, the
// server wraps its inbound listener(s) so each accepted connection's PROXY v1/v2
// header recovers the real client IP (honored ONLY from a trusted peer). When nil,
// no wrapper is installed and the accept path is unchanged (zero cost). It can also
// be supplied by the `-proxy-protocol` + `-proxy-protocol-trust` run flags, which
// the run command merges into this field before constructing the server.
ProxyProtocol *ProxyProtocolConfig
// Server is the parsed global `server { maxconn N; read_timeout D; idle_timeout D }`
// block (the inbound data-plane connection knobs), or NIL when absent (the common
// case). When set, the server overrides its hardcoded inbound http.Server timeouts
// from the non-zero fields and wraps the public listener(s) with a LimitListener
// when maxconn>0. When nil, the shipped default constants apply and no limiter is
// installed (zero cost). It governs the data plane only — the admin server keeps
// its own configuration.
Server *ServerConfig
// GlobalDirectiveWarnings are load-time WARNINGS for every top-level directive in
// the leading global-options block that no consumer reads — dead config that loads
// clean but never takes effect (the CAD-62 trap: a global `trust_proxy` that
// silently did nothing behind Cloudflare). Computed at load via
// cadishfile.UnconsumedGlobalDirectives — the SAME detector `cadish check` uses, so
// check and run agree — and surfaced by the `cadish run` command as log.Warn lines
// (the config still loads; these are observability only, mirroring
// AdminExposureWarning). Empty for a clean config.
GlobalDirectiveWarnings []string
// contains filtered or unexported fields
}
Config is a loaded, ready-to-serve configuration: one runtime Site per site block in the Cadishfile, plus any temp directories created for RAM-only caches (removed by Close).
func FailingK8sConfigForTest ¶
func FailingK8sConfigForTest() *Config
FailingK8sConfigForTest returns a *Config whose Start(ctx) always fails, as if the Kubernetes informer caches never synced. It is a cross-package test seam for the server's startup fail-fast path (internal/server); production code never calls it.
func Load ¶
Load reads, validates and compiles the Cadishfile at path. Every error carries a source position where possible. The returned *Config owns cache stores that the caller MUST Close (via Config.Close) at shutdown. It is LoadWithOptions with the zero options (in-cluster/KUBECONFIG/~/.kube/config for any k8s:// target).
func LoadString ¶
LoadString compiles a Cadishfile held in memory (no file read), through the exact same parse + env-substitute + compile path as Load. name is used for file:line diagnostics (e.g. "<ingress>"). It is the seam the ingress controller renders into: the translator emits Cadishfile text and LoadString turns it into a ready *Config. Imports/geo file references resolve relative to the process working directory.
func LoadStringWithOptions ¶
func LoadStringWithOptions(name, src string, opts LoadOptions) (*Config, error)
LoadStringWithOptions is LoadString with explicit run-time options (e.g. the --kubeconfig path so a generated k8s:// upstream resolves out-of-cluster).
func LoadWithOptions ¶
func LoadWithOptions(path string, opts LoadOptions) (*Config, error)
LoadWithOptions is Load with explicit run-time options (e.g. the --kubeconfig path for out-of-cluster k8s:// resolution).
func (*Config) CacheBudgetChanges ¶ added in v0.2.1
func (c *Config) CacheBudgetChanges(old *Config) []CacheBudgetChange
CacheBudgetChanges reports, for every site that SURVIVES a reload from old onto c (matched by primary host with an UNCHANGED cache-key fingerprint — i.e. exactly the sites whose warm store TransplantStoresFrom carries over), whether the new RAM budget, disk budget or disk PATH differs from the running store. Because the warm store is transplanted as-is and cache.Store has no live resize, such a difference NEVER takes effect until restart, so ApplyConfig logs it. A site whose fingerprint CHANGED is not reported: its store is flushed and the freshly-built cold store (new budget/path) is used, so the change DOES apply. A scratch temp dir (a site with no `disk` directive) is treated as "no configured path" on both sides, so a per-reload random temp dir is never mistaken for a path change.
Call it BEFORE TransplantStoresFrom, which overwrites c.Sites' Store with old's warm store (after which the cold budget/path is no longer observable).
func (*Config) Close ¶
Close releases every site's cache store and removes temp directories. Safe to call once; errors are joined into the first non-nil.
func (*Config) CloseExcept ¶
CloseExcept releases this config's cache stores and temp directories, SKIPPING any store present in keep. It exists for zero-downtime reload: when a site survives a reload its warm cache.Store is transplanted onto the new config, so the old config must be torn down WITHOUT closing that preserved store (closing it would cold the cache, defeating the reload). A store that was transplanted out is in keep and is left open; its temp dir (if any) is likewise still in use, so removal of temp dirs is governed by the same keep set (a temp dir whose store is preserved is kept).
keep may be nil (close everything — the plain shutdown path). Errors are joined into the first non-nil.
func (*Config) ClusterListenAddrs ¶ added in v0.2.3
ClusterListenAddrs returns the DISTINCT dedicated peer-listener addresses declared by `cluster { listen … }` across all sites, in first-seen order. The server opens one plain-HTTP peer listener per address at startup. Empty when no site declares `listen` (the k8s / plain-data-listener topology).
func (*Config) ClusterRegions ¶ added in v0.2.3
ClusterRegions returns the set of cluster regions (the X-Cadish-Peer marker values) across all sites. The dedicated peer listener admits ONLY requests whose hop marker is one of these regions (server.peerListenHandler), rejecting all other traffic.
func (*Config) Clusters ¶ added in v0.2.3
func (c *Config) Clusters() []*cluster.Membership
Clusters returns every cluster.Membership across all sites (read-only). The server uses it at startup to validate that each membership's `self` port is served by a listener the process will open (cluster.Config.ValidatePeerReachable).
func (*Config) Pools ¶
Pools returns every lb.Upstream load-balancer pool across all sites, for observability (the admin dashboard reads each pool's HealthSnapshot). The slice is the live backing slice; callers must treat it as read-only.
func (*Config) Start ¶
Start launches background workers for every lb.Upstream (active health probing and dynamic DNS re-resolution). They run until ctx is cancelled. Idempotent per pool. Safe to call on a config with no lb pools (a no-op).
When a k8s:// target exists it FIRST starts the shared K8s client and blocks on its informer cache sync, returning that error (fail-fast: a config that can't reach the API or lacks RBAC must not start serving with empty k8s pools). Pools and clusters only start after the client is healthy.
func (*Config) StartShared ¶
StartShared starts the config's NON-pool background workers: the shared K8s client (blocking on its informer cache sync, fail-fast) and every cluster membership. It is the part of Start that is NOT diffed across a reload — pools are started separately, per-pool, by the server so steady upstreams survive a reload (see TransplantPoolsFrom). K8s is started before clusters; clusters never error.
Start = StartShared + start every pool under ctx; the server uses StartShared plus per-pool contexts instead, so a transplanted pool keeps running when the config that originally started it is torn down.
func (*Config) TotalRAMCacheBytes ¶
TotalRAMCacheBytes is the sum of every site's configured RAM-tier cache budget. It is the dominant component of cadish's live heap, so the run path uses it to size the GOMEMLIMIT soft limit (D45). Sites without a store contribute nothing. The sum saturates at math.MaxInt64 rather than overflowing.
func (*Config) TransplantPoolsFrom ¶
TransplantPoolsFrom moves UNCHANGED lb pools from old onto c (the freshly loaded config), so a reload does not re-probe steady backends. A pool in c is "unchanged" iff old has a pool with the SAME name AND the SAME content fingerprint (lb.Upstream.Fingerprint — name, target set, policy/shard/replicas, health, host-header, max_conns, timeouts). For every such survivor the live old *lb.Upstream instance — with its warm health FSM, ejection windows, inflight accounting, consistent-hash ring and already-running goroutines — replaces the cold instance config.Load just built, BOTH in c.pools and everywhere the origin graph references it (each site's Origins map and default Origin, descending into origin chains). Genuinely-new pools (new name, or same name with a changed fingerprint) are left in c.pools as the cold instances the server then Starts.
It mutates ONLY c (it reads old purely to match): the survivor instances are shared between old and c during the swap window, which is safe because an *lb.Upstream is concurrency-safe and the server never cancels a survivor's goroutines (only genuinely-removed pools are stopped, after the swap). Call it BEFORE starting c's pools so the server starts only the added ones.
func (*Config) TransplantStoresFrom ¶
TransplantStoresFrom moves the WARM cache store from each of old's sites onto the matching site in c (matched by primary host), for zero-downtime reload: c is the freshly loaded config and old is the one currently serving. For every carried-over site, the cold store config.Load just opened for c is closed and its scratch temp dir (if any) removed, and old's warm store + freshness keep serving through the handler swap. Sites only in old (removed) or only in c (added) are untouched.
It mutates c.Sites' Store fields and c.tempDirs (dropping orphaned scratch dirs). Call it BEFORE the handler routing swap so the new routing points at warm stores.
type LoadOptions ¶
type LoadOptions struct {
// Kubeconfig is the explicit kubeconfig path used to resolve k8s:// upstreams
// out-of-cluster (the --kubeconfig flag). Empty ⇒ in-cluster, then KUBECONFIG,
// then ~/.kube/config. It is only consulted when the config has a k8s:// target.
Kubeconfig string
// EndpointResolver, when non-nil, supplies the k8s:// EndpointResolver directly
// instead of building a shared k8s.Client. The ingress controller passes Layer 1's
// already-built client's resolver (so the translated config reuses one client);
// tests inject a fake so a k8s:// config compiles offline. When set, this config's
// Start/Close do NOT manage the resolver's client — its owner does.
EndpointResolver lb.EndpointResolver
// AllowNoSites permits a config that defines ZERO sites. The ingress controller uses
// it: its base Cadishfile holds only globals (sites come from Ingress objects), and a
// reconcile with no matched Ingresses renders a site-less config that must still load
// (the server then serves nothing until Ingresses appear). For a normal `cadish run`
// it stays false, so a site-less Cadishfile is the usual fail-fast error.
AllowNoSites bool
}
LoadOptions tunes Load behavior with knobs that come from run-time flags rather than the Cadishfile itself.
type ProxyProtocolConfig ¶
type ProxyProtocolConfig struct {
// Trust is the trusted PROXY-header source CIDRs (typically the LB addresses).
Trust []netip.Prefix
}
ProxyProtocolConfig is the parsed global `proxy_protocol { … }` option: the opt-in PROXY-protocol listener (recover the real client IP behind an L4/TCP-passthrough LB). It is NIL when no block is present (the common case) — the listener wrapper is then never installed and the accept path is byte-for-byte unchanged (zero cost).
SECURITY (load-bearing): Trust is the set of trusted PROXY-header source CIDRs. A PROXY header is honored ONLY from a peer in this set; from anyone else it is rejected (REQUIRE policy). The set is REQUIRED and non-empty — an enabled proxy_protocol with an empty `trust` is a config error here, because an empty set would let any peer forge its source address.
func ParseProxyProtocolFlag ¶
func ParseProxyProtocolFlag(trust string) (*ProxyProtocolConfig, error)
ParseProxyProtocolFlag builds a ProxyProtocolConfig from the `-proxy-protocol-trust` run flag (a comma-separated CIDR list). It enforces the same REQUIRE-non-empty security rule as the Cadishfile block: an empty trust set is an error (an enabled PROXY listener with no trusted sources would let any peer forge its client IP).
type SecurityConfig ¶
type SecurityConfig struct {
// AuditLogPath is the `audit_log <dir|file|off>` target. "" / "off" means the
// audit log is disabled (the default). A directory writes
// <dir>/security-audit.log; a file path appends to that file. OFF by default
// because the audit log MAY record the real client IP (recording who was
// blocked is the point) — an operator must opt in explicitly.
AuditLogPath string
}
SecurityConfig is the parsed global `security { … }` block (WAF v1c, D52). It is NIL when no security block is present (the common case) — the audit log is OFF by default and the datapath pays nothing. The native security PRIMITIVES (allow / deny / rate_limit) are site-level directives and are NOT gated by this block; this block carries only cross-cutting security OBSERVABILITY for v1 (the audit log).
type ServerConfig ¶ added in v0.2.1
type ServerConfig struct {
// MaxConn caps the number of simultaneously-accepted inbound connections on the
// public data-plane listener(s) via golang.org/x/net/netutil.LimitListener.
// 0 (the default / omitted) means NO limit — the bare listener, unchanged.
MaxConn int
// ReadTimeout overrides the inbound http.Server ReadTimeout (a slow-request /
// slowloris bound). 0 (omitted) ⇒ the server's default const is kept.
ReadTimeout time.Duration
// IdleTimeout overrides the inbound http.Server IdleTimeout (how long a keep-alive
// connection may sit idle). 0 (omitted) ⇒ the server's default const is kept.
IdleTimeout time.Duration
}
ServerConfig is the parsed global `server { … }` block: the inbound (data-plane) connection knobs HAProxy exposes as `maxconn` + read/idle timeouts. It is NIL when no block is present (the common case) — the server then uses its hardcoded default constants and installs no connection limiter, so the accept path is byte-for-byte unchanged (zero cost).
Every field is OPTIONAL and zero-valued when omitted; the server resolves a zero field to the CURRENT default constant (read_timeout/idle_timeout) or to "no limit" (maxconn 0). So an absent block — or an omitted field — keeps the shipped defaults.
type Site ¶
type Site struct {
// Addresses are the site header tokens (e.g. "example.com", "*.cdn.example.com"),
// used for Host-based site selection.
Addresses []string
// Name is a short identifier for logs (the first address).
Name string
// Pipeline is the compiled request-evaluation engine for this site.
Pipeline *pipeline.Pipeline
// Store is the two-tier cache for this site.
Store *cache.Store
// Origin is the default upstream origin (a single httporigin/s3origin, or a
// chain when `origin chain …` is configured). Used when no `route` matched or
// the routed upstream is unknown.
Origin origin.Origin
// Origins maps each declared upstream name to its origin, so a `route @m ->
// NAME` decision can select the matching backend. A chain's member upstreams
// also appear here.
Origins map[string]origin.Origin
// DefaultUpstreamName is the name of the default origin's upstream ("" when the
// default is an `origin chain`). The server resolves a request's effective
// upstream name as routedUpstream-or-DefaultUpstreamName to look up its sticky
// spec for the lb routing-key seam.
DefaultUpstreamName string
// StickySpecs maps a sticky upstream's name to the spec telling the server how
// to derive the {sticky} routing key (which cookie / client_ip fallback) to
// attach via lb.WithRoutingKey before Fetch.
StickySpecs map[string]*lb.StickySpec
// Device is the site's User-Agent → device-class classifier for the {device}
// cache-key normalizer (built from `device_detect { … }`, or the built-in
// default ruleset when absent). Never nil. The server consults it (gated by
// Pipeline.UsesDeviceToken) to set Request.Device before EvalRequest.
Device *classify.Classifier
// Geo is the site's client-IP/header → country-class source for the {geo}
// cache-key normalizer (built from `geo { … }`). It is NIL when the site
// configures no geo source — the geo tokens then render "". The server consults
// it (gated by Pipeline.UsesGeoToken) to set Request.Geo before EvalRequest, and
// derives Request.GeoContinent from the country via an in-tree table.
Geo geo.Source
// GeoRegion is the site's upstream region/subdivision-header source for the
// {geo.region} token / `geo region …` matcher (from `geo { region_header NAME }`).
// It is NIL when no region_header is configured — {geo.region} then renders "".
// Region needs an upstream geo header because a US state can't come from a raw IP
// without a GeoIP DB (D11: no bundled GeoIP database). Set into Request.GeoRegion
// in the same gated geo pre-pass.
GeoRegion geo.Source
// TrustedProxies are the CIDRs whose X-Forwarded-For is trusted when resolving
// the real client IP. It is the SINGLE SOURCE OF TRUTH for trusted-proxy
// resolution, read by BOTH {geo} (the geo pre-pass) and the security gate's `ip`
// ACL. It is the UNION of the standalone site-level `trust_proxy …` directive and
// the `geo { trust_proxy … }` block, so a pure-security site (an `ip` ACL with no
// geo block) can still declare its proxies.
TrustedProxies []netip.Prefix
// Cluster is the region-local peer-cache membership built from a `cluster { … }`
// block, or NIL when the site declares no cluster (the zero-cost default: a
// non-clustered cadish behaves exactly as before). When non-nil it drives peer
// read-through (#7) and ownership routing (#8); the server consults it in one
// well-named seam (clusterRoute) and the read-through PeerOrigin is already
// composed before the real origin in this site's Origin chain.
Cluster *cluster.Membership
// PoolHealthy resolves an upstream POOL name to its current liveness (≥1 backend
// up, lb nbsrv()>0) for the `upstream_healthy NAME…` matcher (the AWS health probe).
// It is built ONLY when the site's pipeline references the matcher (gated by
// Pipeline.NeedsPoolHealth) — NIL on every other site, so the request fast path pays
// nothing. The server injects it into Request.PoolHealthy before EvalRequest. It reads
// this site's Origins map at CALL time, so it always resolves to the LIVE pool after a
// reload pool transplant (which repoints Origins in place); a name that is not a pool
// resolves false (fail-closed).
PoolHealthy func(name string) bool
// contains filtered or unexported fields
}
Site is one runtime site: its host addresses, compiled pipeline, cache store and origin. It is immutable after Load and safe for concurrent use by the server.