Skip to content

Commit 79cbe7b

Browse files
committed
httpcaddyfile: Add 'vars' directive
See discussion in #4650
1 parent 55b4c12 commit 79cbe7b

File tree

4 files changed

+87
-7
lines changed

4 files changed

+87
-7
lines changed

caddyconfig/httpcaddyfile/builtins.go

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,7 @@ func init() {
3939
RegisterDirective("bind", parseBind)
4040
RegisterDirective("tls", parseTLS)
4141
RegisterHandlerDirective("root", parseRoot)
42+
RegisterHandlerDirective("vars", parseVars)
4243
RegisterHandlerDirective("redir", parseRedir)
4344
RegisterHandlerDirective("respond", parseRespond)
4445
RegisterHandlerDirective("abort", parseAbort)
@@ -530,6 +531,13 @@ func parseRoot(h Helper) (caddyhttp.MiddlewareHandler, error) {
530531
return caddyhttp.VarsMiddleware{"root": root}, nil
531532
}
532533

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+
533541
// parseRedir parses the redir directive. Syntax:
534542
//
535543
// redir [<matcher>] <to> [<code>]

caddyconfig/httpcaddyfile/directives.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,7 @@ var directiveOrder = []string{
4040
"tracing",
4141

4242
"map",
43+
"vars",
4344
"root",
4445

4546
"header",

caddytest/integration/caddyfile_adapt/map_with_raw_types.txt renamed to caddytest/integration/caddyfile_adapt/map_and_vars_with_raw_types.txt

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,14 @@ map {host} {my_placeholder} {magic_number} {
1919
# Should output two strings, second being escaped quote
2020
default "unknown domain" \"""
2121
}
22+
23+
vars foo bar
24+
vars {
25+
abc true
26+
def 1
27+
ghi 2.3
28+
jkl "mn op"
29+
}
2230
----------
2331
{
2432
"apps": {
@@ -91,6 +99,17 @@ map {host} {my_placeholder} {magic_number} {
9199
}
92100
],
93101
"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"
94113
}
95114
]
96115
}

modules/caddyhttp/vars.go

Lines changed: 59 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,7 @@ func init() {
3737
//
3838
// The key is the variable name, and the value is the value of the
3939
// variable. Both the name and value may use or contain placeholders.
40-
type VarsMiddleware map[string]string
40+
type VarsMiddleware map[string]interface{}
4141

4242
// CaddyModule returns the Caddy module information.
4343
func (VarsMiddleware) CaddyModule() caddy.ModuleInfo {
@@ -47,17 +47,67 @@ func (VarsMiddleware) CaddyModule() caddy.ModuleInfo {
4747
}
4848
}
4949

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 {
5151
vars := r.Context().Value(VarsCtxKey).(map[string]interface{})
5252
repl := r.Context().Value(caddy.ReplacerCtxKey).(*caddy.Replacer)
53-
for k, v := range t {
53+
for k, v := range m {
5454
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
5759
}
5860
return next.ServeHTTP(w, r)
5961
}
6062

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+
61111
// VarsMatcher is an HTTP request matcher which can match
62112
// requests based on variables in the context. The key is
63113
// the name of the variable, and the values are possible
@@ -261,6 +311,8 @@ func SetVar(ctx context.Context, key string, value interface{}) {
261311

262312
// Interface guards
263313
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)
266318
)

0 commit comments

Comments
 (0)