summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMatthew Holt <mholt@users.noreply.github.com>2022-03-22 10:47:21 -0600
committerMatthew Holt <mholt@users.noreply.github.com>2022-03-22 10:47:21 -0600
commit79cbe7bfd06565d0e7ab0717119f78960ed54c08 (patch)
tree4f2b333e5419ad3c3a7c0cc4ea4398afbc61c340
parent55b4c12e0404347828ed691594d1f8ae8228c598 (diff)
httpcaddyfile: Add 'vars' directive
See discussion in #4650
-rw-r--r--caddyconfig/httpcaddyfile/builtins.go8
-rw-r--r--caddyconfig/httpcaddyfile/directives.go1
-rw-r--r--caddytest/integration/caddyfile_adapt/map_and_vars_with_raw_types.txt (renamed from caddytest/integration/caddyfile_adapt/map_with_raw_types.txt)19
-rw-r--r--modules/caddyhttp/vars.go66
4 files changed, 87 insertions, 7 deletions
diff --git a/caddyconfig/httpcaddyfile/builtins.go b/caddyconfig/httpcaddyfile/builtins.go
index e1430d0..e65039d 100644
--- a/caddyconfig/httpcaddyfile/builtins.go
+++ b/caddyconfig/httpcaddyfile/builtins.go
@@ -39,6 +39,7 @@ func init() {
RegisterDirective("bind", parseBind)
RegisterDirective("tls", parseTLS)
RegisterHandlerDirective("root", parseRoot)
+ RegisterHandlerDirective("vars", parseVars)
RegisterHandlerDirective("redir", parseRedir)
RegisterHandlerDirective("respond", parseRespond)
RegisterHandlerDirective("abort", parseAbort)
@@ -530,6 +531,13 @@ func parseRoot(h Helper) (caddyhttp.MiddlewareHandler, error) {
return caddyhttp.VarsMiddleware{"root": root}, nil
}
+// parseVars parses the vars directive. See its UnmarshalCaddyfile method for syntax.
+func parseVars(h Helper) (caddyhttp.MiddlewareHandler, error) {
+ v := new(caddyhttp.VarsMiddleware)
+ err := v.UnmarshalCaddyfile(h.Dispenser)
+ return v, err
+}
+
// parseRedir parses the redir directive. Syntax:
//
// redir [<matcher>] <to> [<code>]
diff --git a/caddyconfig/httpcaddyfile/directives.go b/caddyconfig/httpcaddyfile/directives.go
index aac4f1f..425bf19 100644
--- a/caddyconfig/httpcaddyfile/directives.go
+++ b/caddyconfig/httpcaddyfile/directives.go
@@ -40,6 +40,7 @@ var directiveOrder = []string{
"tracing",
"map",
+ "vars",
"root",
"header",
diff --git a/caddytest/integration/caddyfile_adapt/map_with_raw_types.txt b/caddytest/integration/caddyfile_adapt/map_and_vars_with_raw_types.txt
index 54b2b60..af9faf4 100644
--- a/caddytest/integration/caddyfile_adapt/map_with_raw_types.txt
+++ b/caddytest/integration/caddyfile_adapt/map_and_vars_with_raw_types.txt
@@ -19,6 +19,14 @@ map {host} {my_placeholder} {magic_number} {
# Should output two strings, second being escaped quote
default "unknown domain" \"""
}
+
+vars foo bar
+vars {
+ abc true
+ def 1
+ ghi 2.3
+ jkl "mn op"
+}
----------
{
"apps": {
@@ -91,6 +99,17 @@ map {host} {my_placeholder} {magic_number} {
}
],
"source": "{http.request.host}"
+ },
+ {
+ "foo": "bar",
+ "handler": "vars"
+ },
+ {
+ "abc": true,
+ "def": 1,
+ "ghi": 2.3,
+ "handler": "vars",
+ "jkl": "mn op"
}
]
}
diff --git a/modules/caddyhttp/vars.go b/modules/caddyhttp/vars.go
index b0f10a7..28d0ddf 100644
--- a/modules/caddyhttp/vars.go
+++ b/modules/caddyhttp/vars.go
@@ -37,7 +37,7 @@ func init() {
//
// The key is the variable name, and the value is the value of the
// variable. Both the name and value may use or contain placeholders.
-type VarsMiddleware map[string]string
+type VarsMiddleware map[string]interface{}
// CaddyModule returns the Caddy module information.
func (VarsMiddleware) CaddyModule() caddy.ModuleInfo {
@@ -47,17 +47,67 @@ func (VarsMiddleware) CaddyModule() caddy.ModuleInfo {
}
}
-func (t VarsMiddleware) ServeHTTP(w http.ResponseWriter, r *http.Request, next Handler) error {
+func (m VarsMiddleware) ServeHTTP(w http.ResponseWriter, r *http.Request, next Handler) error {
vars := r.Context().Value(VarsCtxKey).(map[string]interface{})
repl := r.Context().Value(caddy.ReplacerCtxKey).(*caddy.Replacer)
- for k, v := range t {
+ for k, v := range m {
keyExpanded := repl.ReplaceAll(k, "")
- valExpanded := repl.ReplaceAll(v, "")
- vars[keyExpanded] = valExpanded
+ if valStr, ok := v.(string); ok {
+ v = repl.ReplaceAll(valStr, "")
+ }
+ vars[keyExpanded] = v
}
return next.ServeHTTP(w, r)
}
+// UnmarshalCaddyfile implements caddyfile.Unmarshaler. Syntax:
+//
+// vars [<name> <val>] {
+// <name> <val>
+// ...
+// }
+//
+func (m *VarsMiddleware) UnmarshalCaddyfile(d *caddyfile.Dispenser) error {
+ if *m == nil {
+ *m = make(VarsMiddleware)
+ }
+
+ nextVar := func(headerLine bool) error {
+ if headerLine {
+ // header line is optional
+ if !d.NextArg() {
+ return nil
+ }
+ }
+ varName := d.Val()
+
+ if !d.NextArg() {
+ return d.ArgErr()
+ }
+ varValue := d.ScalarVal()
+
+ (*m)[varName] = varValue
+
+ if d.NextArg() {
+ return d.ArgErr()
+ }
+ return nil
+ }
+
+ for d.Next() {
+ if err := nextVar(true); err != nil {
+ return err
+ }
+ for nesting := d.Nesting(); d.NextBlock(nesting); {
+ if err := nextVar(false); err != nil {
+ return err
+ }
+ }
+ }
+
+ return nil
+}
+
// VarsMatcher is an HTTP request matcher which can match
// requests based on variables in the context. The key is
// the name of the variable, and the values are possible
@@ -261,6 +311,8 @@ func SetVar(ctx context.Context, key string, value interface{}) {
// Interface guards
var (
- _ MiddlewareHandler = (*VarsMiddleware)(nil)
- _ RequestMatcher = (*VarsMatcher)(nil)
+ _ MiddlewareHandler = (*VarsMiddleware)(nil)
+ _ caddyfile.Unmarshaler = (*VarsMiddleware)(nil)
+ _ RequestMatcher = (*VarsMatcher)(nil)
+ _ caddyfile.Unmarshaler = (*VarsMatcher)(nil)
)