From a33e4b542689cbe7ac711e3cfde1d2a30c0156ae Mon Sep 17 00:00:00 2001 From: Mohammed Al Sahaf Date: Sat, 26 Sep 2020 02:50:26 +0300 Subject: [PATCH] caddyfile: Add support for `vars` and `vars_regexp` matchers (#3730) * caddyfile: support vars and vars_regexp matchers in the caddyfile * caddyfile: matchers: Brian Kernighan said printf is good debugging tool but didn't say keep them around --- .../caddyfile_adapt/matcher_syntax.txt | 59 +++++++++++++++++++ modules/caddyhttp/matchers.go | 2 + modules/caddyhttp/vars.go | 48 +++++++++++++++ 3 files changed, 109 insertions(+) diff --git a/caddytest/integration/caddyfile_adapt/matcher_syntax.txt b/caddytest/integration/caddyfile_adapt/matcher_syntax.txt index 8cabc582..53ec0232 100644 --- a/caddytest/integration/caddyfile_adapt/matcher_syntax.txt +++ b/caddytest/integration/caddyfile_adapt/matcher_syntax.txt @@ -9,6 +9,15 @@ @matcher3 not method PUT respond @matcher3 "not put" + + @matcher4 vars "{http.request.uri}" "/vars-matcher" + respond @matcher4 "from vars matcher" + + @matcher5 vars_regexp static "{http.request.uri}" `\.([a-f0-9]{6})\.(css|js)$` + respond @matcher5 "from vars_regexp matcher with name" + + @matcher6 vars_regexp "{http.request.uri}" `\.([a-f0-9]{6})\.(css|js)$` + respond @matcher6 "from vars_regexp matcher without name" } ---------- { @@ -68,6 +77,56 @@ "handler": "static_response" } ] + }, + { + "match": [ + { + "vars": { + "{http.request.uri}": "/vars-matcher" + } + } + ], + "handle": [ + { + "body": "from vars matcher", + "handler": "static_response" + } + ] + }, + { + "match": [ + { + "vars_regexp": { + "{http.request.uri}": { + "name": "static", + "pattern": "\\.([a-f0-9]{6})\\.(css|js)$" + } + } + } + ], + "handle": [ + { + "body": "from vars_regexp matcher with name", + "handler": "static_response" + } + ] + }, + { + "match": [ + { + "vars_regexp": { + "{http.request.uri}": { + "pattern": "\\.([a-f0-9]{6})\\.(css|js)$" + } + } + } + ], + "handle": [ + { + "body": "from vars_regexp matcher without name", + "handler": "static_response" + } + ] } ] } diff --git a/modules/caddyhttp/matchers.go b/modules/caddyhttp/matchers.go index 164f4434..a8320242 100644 --- a/modules/caddyhttp/matchers.go +++ b/modules/caddyhttp/matchers.go @@ -927,6 +927,8 @@ var ( _ caddyfile.Unmarshaler = (*MatchHeaderRE)(nil) _ caddyfile.Unmarshaler = (*MatchProtocol)(nil) _ caddyfile.Unmarshaler = (*MatchRemoteIP)(nil) + _ caddyfile.Unmarshaler = (*VarsMatcher)(nil) + _ caddyfile.Unmarshaler = (*MatchVarsRE)(nil) _ json.Marshaler = (*MatchNot)(nil) _ json.Unmarshaler = (*MatchNot)(nil) diff --git a/modules/caddyhttp/vars.go b/modules/caddyhttp/vars.go index 9561d46c..479ef0a7 100644 --- a/modules/caddyhttp/vars.go +++ b/modules/caddyhttp/vars.go @@ -20,6 +20,7 @@ import ( "net/http" "github.com/caddyserver/caddy/v2" + "github.com/caddyserver/caddy/v2/caddyconfig/caddyfile" ) func init() { @@ -64,6 +65,24 @@ func (VarsMatcher) CaddyModule() caddy.ModuleInfo { } } +// UnmarshalCaddyfile implements caddyfile.Unmarshaler. +func (m *VarsMatcher) UnmarshalCaddyfile(d *caddyfile.Dispenser) error { + if *m == nil { + *m = make(map[string]string) + } + for d.Next() { + var field, val string + if !d.Args(&field, &val) { + return d.Errf("malformed vars matcher: expected both field and value") + } + (*m)[field] = val + if d.NextBlock(0) { + return d.Err("malformed vars matcher: blocks are not supported") + } + } + return nil +} + // Match matches a request based on variables in the context. func (m VarsMatcher) Match(r *http.Request) bool { vars := r.Context().Value(VarsCtxKey).(map[string]interface{}) @@ -106,6 +125,35 @@ func (MatchVarsRE) CaddyModule() caddy.ModuleInfo { } } +// UnmarshalCaddyfile implements caddyfile.Unmarshaler. +func (m *MatchVarsRE) UnmarshalCaddyfile(d *caddyfile.Dispenser) error { + if *m == nil { + *m = make(map[string]*MatchRegexp) + } + for d.Next() { + var first, second, third string + if !d.Args(&first, &second) { + return d.ArgErr() + } + + var name, field, val string + if d.Args(&third) { + name = first + field = second + val = third + } else { + field = first + val = second + } + + (*m)[field] = &MatchRegexp{Pattern: val, Name: name} + if d.NextBlock(0) { + return d.Err("malformed vars_regexp matcher: blocks are not supported") + } + } + return nil +} + // Provision compiles m's regular expressions. func (m MatchVarsRE) Provision(ctx caddy.Context) error { for _, rm := range m {