caddyserver/caddy
Replacer
caddy.Replacer is the placeholder engine. It's how almost every config field becomes runtime-aware — {http.request.uri.path}, {env.HOME}, {file.api_key} all run through it.
Purpose
Resolve {token} placeholders in strings to live values. Plug-in providers contribute new placeholders without changing the core. The same Replacer instance threads through provisioning and request handling, so a value like tls {env.MY_DOMAIN} works.
Directory layout
| Path | Role |
|---|---|
replacer.go |
The core Replacer: provider chain, static map, format helpers (~12 KB) |
modules/caddyhttp/replacer.go |
HTTP-specific placeholder providers (~19 KB) |
replacer_fuzz.go |
Fuzz harness for the parser |
Key abstractions
| Type | Where | Description |
|---|---|---|
Replacer |
replacer.go |
Holds a list of replacementProviders + a static map[string]any |
replacementProvider |
replacer.go |
Internal interface: replace(key string) (any, bool) |
globalDefaultReplacementProvider |
replacer.go |
Built-in placeholders: system.*, time.*, host.*, random.* |
| HTTP request placeholder funcs | modules/caddyhttp/replacer.go |
http.request.*, http.response.*, tls.client.* |
How it works
graph LR
Caller -->|"ReplaceAll(input, '')"| Replacer
Replacer --> Static["static map<br/>(set via Set)"]
Replacer --> Providers
Providers --> Default[globalDefaultReplacementProvider]
Providers --> ContextProv[per-request providers]
Static -->|first hit wins| Out[output string]
Providers -->|fallback| OutA new replacer comes from caddy.NewReplacer(). Modules append providers with rep.Map(func(key string) (any, bool)) for context-specific lookups (e.g. the HTTP server appends a per-request provider that knows how to read request headers).
The static map is populated with rep.Set(key, value). It takes precedence over providers, so a route can override http.request.uri for downstream handlers.
ReplaceAll(input, empty) walks input, finds {...} tokens (with default value support {key:fallback}), and substitutes. Unknown tokens are replaced with empty if non-empty, otherwise left alone.
Variants: ReplaceKnown only substitutes recognized tokens, ReplaceFunc lets you intercept each substitution.
Built-in tokens (selection)
From replacer.go's globalDefaultReplacementProvider:
{system.hostname},{system.slash},{system.os},{system.arch},{system.wd}{time.now},{time.now.unix},{time.now.year},{time.now.iso_local},{time.now.common_log}{host.ip}— interface IPs.{env.NAME}— environment variables.{file.path}— read a file's contents (with size cap; useful for secrets).
From modules/caddyhttp/replacer.go (per-request provider):
{http.request.host},{http.request.method},{http.request.uri},{http.request.uri.path},{http.request.uri.path.<n>},{http.request.uri.query}{http.request.header.<name>},{http.request.cookie.<name>}{http.request.remote.host},{http.request.remote.port},{http.request.client_ip}{http.request.body},{http.request.body_base64}— debugging only{http.request.tls.version},{http.request.tls.client.subject}, etc.{http.response.status},{http.response.header.<name>}{http.error.status_code},{http.error.message}— inside error routes{http.matchers.<name>...}— values captured by named matchers
Integration points
- HTTP server:
Server.ServeHTTP(server.go) creates a per-request replacer, attaches the HTTP provider, and stores it in the request context. Handlers read it viacaddy.NewReplacerlookups orcaddyhttp.GetVar. - Caddyfile adapter: placeholders are passed through verbatim. They aren't resolved until provisioning or runtime.
- Modules' Provision: any module that wants to support placeholders in its config calls
repl.ReplaceAllon its values insideProvision. Examples:modules/caddyhttp/headers/headers.go,modules/caddyhttp/reverseproxy/reverseproxy.go.
Entry points for modification
- Add a global token? Extend
globalDefaultReplacementProvider.replaceinreplacer.go. - Add an HTTP token? Edit
modules/caddyhttp/replacer.go's per-request provider. - Make a module's config placeholder-aware? Call
repl.ReplaceAll(field, "")on the field duringProvision.
Related pages
Built by Factory AutoWiki from public repository content. It is a generated preview for codebase exploration, not source-maintained documentation.