From 79cbe7bfd06565d0e7ab0717119f78960ed54c08 Mon Sep 17 00:00:00 2001 From: Matthew Holt Date: Tue, 22 Mar 2022 10:47:21 -0600 Subject: httpcaddyfile: Add 'vars' directive See discussion in #4650 --- modules/caddyhttp/vars.go | 66 ++++++++++++++++++++++++++++++++++++++++++----- 1 file changed, 59 insertions(+), 7 deletions(-) (limited to 'modules/caddyhttp/vars.go') 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 [ ] { +// +// ... +// } +// +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) ) -- cgit v1.2.3