Fast and extensible multi-platform HTTP/1-2-3 web server with automatic HTTPS
Mirrored from https://github.com/Slazee/caddy.git
Synced Nov 13, 20:30 UTC
httpcaddyfile: Add 'vars' directive
See discussion in #4650
Matthew Holt committed
Mar 22, 2022 at 10:47 UTC
79cbe7bfd06565d0e7ab0717119f78960ed54c08
4 files changed
+87
-7
caddyconfig/httpcaddyfile/builtins.go
+8
@@ -39,6 +39,7 @@ func init() {
39
RegisterDirective("bind", parseBind)
40
RegisterDirective("tls", parseTLS)
41
RegisterHandlerDirective("root", parseRoot)
42
+ RegisterHandlerDirective("vars", parseVars)
43
RegisterHandlerDirective("redir", parseRedir)
44
RegisterHandlerDirective("respond", parseRespond)
45
RegisterHandlerDirective("abort", parseAbort)
@@ -530,6 +531,13 @@ func parseRoot(h Helper) (caddyhttp.MiddlewareHandler, error) {
531
return caddyhttp.VarsMiddleware{"root": root}, nil
532
}
533
534
+// parseVars parses the vars directive. See its UnmarshalCaddyfile method for syntax.
535
+func parseVars(h Helper) (caddyhttp.MiddlewareHandler, error) {
536
+ v := new(caddyhttp.VarsMiddleware)
537
+ err := v.UnmarshalCaddyfile(h.Dispenser)
538
+ return v, err
539
+}
540
+
541
// parseRedir parses the redir directive. Syntax:
542
//
543
// redir [<matcher>] <to> [<code>]
caddyconfig/httpcaddyfile/directives.go
+1
@@ -40,6 +40,7 @@ var directiveOrder = []string{
40
"tracing",
41
42
"map",
43
+ "vars",
44
"root",
45
46
"header",
caddytest/integration/caddyfile_adapt/map_and_vars_with_raw_types.txt
renamed
+19
@@ -19,6 +19,14 @@ map {host} {my_placeholder} {magic_number} {
19
# Should output two strings, second being escaped quote
20
default "unknown domain" \"""
21
}
22
+
23
+vars foo bar
24
+vars {
25
+ abc true
26
+ def 1
27
+ ghi 2.3
28
+ jkl "mn op"
29
+}
30
----------
31
{
32
"apps": {
@@ -91,6 +99,17 @@ map {host} {my_placeholder} {magic_number} {
99
}
100
],
101
"source": "{http.request.host}"
102
+ },
103
+ {
104
+ "foo": "bar",
105
+ "handler": "vars"
106
+ },
107
+ {
108
+ "abc": true,
109
+ "def": 1,
110
+ "ghi": 2.3,
111
+ "handler": "vars",
112
+ "jkl": "mn op"
113
}
114
]
115
}
modules/caddyhttp/vars.go
+59
-7
@@ -37,7 +37,7 @@ func init() {
37
//
38
// The key is the variable name, and the value is the value of the
39
// variable. Both the name and value may use or contain placeholders.
40
-type VarsMiddleware map[string]string
40
+type VarsMiddleware map[string]interface{}
41
42
// CaddyModule returns the Caddy module information.
43
func (VarsMiddleware) CaddyModule() caddy.ModuleInfo {
@@ -47,17 +47,67 @@ func (VarsMiddleware) CaddyModule() caddy.ModuleInfo {
47
}
48
}
49
50
-func (t VarsMiddleware) ServeHTTP(w http.ResponseWriter, r *http.Request, next Handler) error {
50
+func (m VarsMiddleware) ServeHTTP(w http.ResponseWriter, r *http.Request, next Handler) error {
51
vars := r.Context().Value(VarsCtxKey).(map[string]interface{})
52
repl := r.Context().Value(caddy.ReplacerCtxKey).(*caddy.Replacer)
53
- for k, v := range t {
53
+ for k, v := range m {
54
keyExpanded := repl.ReplaceAll(k, "")
55
- valExpanded := repl.ReplaceAll(v, "")
56
- vars[keyExpanded] = valExpanded
55
+ if valStr, ok := v.(string); ok {
56
+ v = repl.ReplaceAll(valStr, "")
57
+ }
58
+ vars[keyExpanded] = v
59
}
60
return next.ServeHTTP(w, r)
61
}
62
63
+// UnmarshalCaddyfile implements caddyfile.Unmarshaler. Syntax:
64
+//
65
+// vars [<name> <val>] {
66
+// <name> <val>
67
+// ...
68
+// }
69
+//
70
+func (m *VarsMiddleware) UnmarshalCaddyfile(d *caddyfile.Dispenser) error {
71
+ if *m == nil {
72
+ *m = make(VarsMiddleware)
73
+ }
74
+
75
+ nextVar := func(headerLine bool) error {
76
+ if headerLine {
77
+ // header line is optional
78
+ if !d.NextArg() {
79
+ return nil
80
+ }
81
+ }
82
+ varName := d.Val()
83
+
84
+ if !d.NextArg() {
85
+ return d.ArgErr()
86
+ }
87
+ varValue := d.ScalarVal()
88
+
89
+ (*m)[varName] = varValue
90
+
91
+ if d.NextArg() {
92
+ return d.ArgErr()
93
+ }
94
+ return nil
95
+ }
96
+
97
+ for d.Next() {
98
+ if err := nextVar(true); err != nil {
99
+ return err
100
+ }
101
+ for nesting := d.Nesting(); d.NextBlock(nesting); {
102
+ if err := nextVar(false); err != nil {
103
+ return err
104
+ }
105
+ }
106
+ }
107
+
108
+ return nil
109
+}
110
+
111
// VarsMatcher is an HTTP request matcher which can match
112
// requests based on variables in the context. The key is
113
// the name of the variable, and the values are possible
@@ -261,6 +311,8 @@ func SetVar(ctx context.Context, key string, value interface{}) {
311
312
// Interface guards
313
var (
264
- _ MiddlewareHandler = (*VarsMiddleware)(nil)
265
- _ RequestMatcher = (*VarsMatcher)(nil)
314
+ _ MiddlewareHandler = (*VarsMiddleware)(nil)
315
+ _ caddyfile.Unmarshaler = (*VarsMiddleware)(nil)
316
+ _ RequestMatcher = (*VarsMatcher)(nil)
317
+ _ caddyfile.Unmarshaler = (*VarsMatcher)(nil)
318
)