From 335e086ae0817b1bc61f7aff7a9c1bacc4ea99e6 Mon Sep 17 00:00:00 2001 From: a Date: Thu, 22 Aug 2024 07:58:05 -0500 Subject: [PATCH] develop: Implementing placeholders (#409) * noot * noot * formatting * links * links * better explained * grammar * grammar * fix ref * more explained * noot * noot * Update src/docs/markdown/extending-caddy/placeholders.md Co-authored-by: Matt Holt * Update src/docs/markdown/extending-caddy/placeholders.md Co-authored-by: Matt Holt * Update src/docs/markdown/extending-caddy/placeholders.md Co-authored-by: Matt Holt * Update src/docs/markdown/extending-caddy/placeholders.md Co-authored-by: Matt Holt * noot * noot * noot * noot * noot * noot * Update src/docs/markdown/extending-caddy/placeholders.md Co-authored-by: Francis Lavoie --------- Co-authored-by: Matt Holt Co-authored-by: Francis Lavoie --- README.md | 9 ++ .../markdown/extending-caddy/placeholders.md | 113 ++++++++++++++++++ src/old/includes/docs/nav.html | 3 +- 3 files changed, 124 insertions(+), 1 deletion(-) create mode 100644 src/docs/markdown/extending-caddy/placeholders.md diff --git a/README.md b/README.md index 8b85e6e..c174a55 100644 --- a/README.md +++ b/README.md @@ -20,4 +20,13 @@ Your first time, you may be prompted for a password. This is so Caddy can serve You can then load [https://localhost](https://localhost) (or whatever address you configured) in your browser. +### Docker + +You can run rootless with docker with +``` +docker stop caddy-website || true && docker rm caddy-website || true +docker run --name caddy-website -it -p 8443:443 -v ./:/wd caddy sh -c "cd /wd && caddy run" +``` + +This will allow you to connect to https://localhost:8443 diff --git a/src/docs/markdown/extending-caddy/placeholders.md b/src/docs/markdown/extending-caddy/placeholders.md new file mode 100644 index 0000000..ba07ba6 --- /dev/null +++ b/src/docs/markdown/extending-caddy/placeholders.md @@ -0,0 +1,113 @@ +--- +title: "Placeholder Support" +--- + +# Placeholders + +In Caddy, placeholders are processed by each individual plugin as needed; they do not automatically work everywhere. + +This means that if you wish for your plugin to support placeholders, you must explicitly add support for them. + +If you are not yet familiar with placeholders, start by reading [here](/docs/conventions#placeholders)! + +## Placeholders Overview + +Placeholders are a string in the format `{foo.bar}` used as dynamic configuration values, which is later evaluated at runtime. + +Placeholders-like strings which start with a dollar sign (`{$FOO}`), are evaulated at Caddyfile parse time, and do not need to be dealt with by your plugin. This is because these are not placeholders, but Caddyfile-specific [environmental variable substitution](/docs/caddyfile/concepts#environment-variables), they just happen to share the `{}` syntax. + +It is therefore important to understand that `{env.HOST}` is inherently different from something like `{$HOST}`. + +As an example, see the following Caddyfile: +```caddyfile +:8080 { + respond {$HOST} 200 +} + +:8081 { + respond {env.HOST} 200 +} +``` + +When you adapt this Caddyfile with `HOST=example caddy adapt` you will get +```json +{ + "apps": { + "http": { + "servers": { + "srv0": { + "listen": [ + ":8080" + ], + "routes": [ + { + "handle": [ + { + "body": "example", + "handler": "static_response", + "status_code": 200 + } + ] + } + ] + }, + "srv1": { + "listen": [ + ":8081" + ], + "routes": [ + { + "handle": [ + { + "body": "{env.HOST}", + "handler": "static_response", + "status_code": 200 + } + ] + } + ] + } + } + } + } +} +``` + +Importantly, look at the `"body"` field in both `srv0` and `srv1`. + +Since `srv0` used `{$HOST}`, the special environmental variable replacement with `$`, the value became `example`, as it was processed during Caddyfile parse time. + +Since `srv1` used `{env.HOST}`, a normal placeholder, it was parsed as its own raw string value, `{env.HOST}` + +Some users may immediately notice that this means it is impossible to use the `{$ENV}` syntax in a JSON config. The solution to this is to process such placeholders at Provision time, which is covered below. + + +## Implementing placeholder support + +You should not process placeholders when ummarshaling your Caddyfile. Instead, unmarshal the placeholders as strings in your configuration and evaluate them during either your module's execution (e.g. `ServeHTTP()` for HTTP handlers, `Match()` for matchers, etc.) or in the `Provision()` step, using a `caddy.Replacer`. + + +### Examples + +In this example, we are using a newly constructed replacer to process placeholders. It has access to [global placeholders](/docs/conventions#placeholders) such as `{env.HOST}`, but NOT request placeholder such as `{http.request.uri}` + +```go +func (g *Gizmo) Provision(ctx caddy.Context) error { + repl := caddy.NewReplacer() + g.Name = repl.ReplaceAll(g.Name,"") + return nil +} +``` + +Here, we extract a replacer out of the `context.Context` inside the `*http.Request`. This replacer not only has access to global placeholders, but also request placeholders such as `{http.request.uri}`. + +```go +func (g *Gizmo) ServeHTTP(w http.ResponseWriter, r *http.Request, next caddyhttp.Handler) error { + repl := r.Context().Value(caddy.ReplacerCtxKey).(*caddy.Replacer) + _, err := w.Write([]byte(repl.ReplaceAll(g.Name,""))) + if err != nil { + return err + } + return next.ServeHTTP(w, r) +} +``` diff --git a/src/old/includes/docs/nav.html b/src/old/includes/docs/nav.html index 59133ab..b9981d3 100644 --- a/src/old/includes/docs/nav.html +++ b/src/old/includes/docs/nav.html @@ -38,7 +38,7 @@
  • Modules
  • JSON Config Structure
  • Automatic HTTPS
  • - +
  • Articles
  • Caddy Architecture
  • Conventions
  • @@ -56,6 +56,7 @@
  • Module Namespaces