@marcel91200 / caddy Mirror · read-only / commits / 79cbe7bf
Fork 0

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 )