diff --git a/caddyconfig/httpcaddyfile/directives.go b/caddyconfig/httpcaddyfile/directives.go index 50e27d62..e74a3fe7 100644 --- a/caddyconfig/httpcaddyfile/directives.go +++ b/caddyconfig/httpcaddyfile/directives.go @@ -16,6 +16,7 @@ package httpcaddyfile import ( "encoding/json" + "fmt" "sort" "github.com/caddyserver/caddy/v2" @@ -93,10 +94,11 @@ func RegisterHandlerDirective(dir string, setupFunc UnmarshalHandlerFunc) { // Caddyfile tokens. type Helper struct { *caddyfile.Dispenser - options map[string]interface{} - warnings *[]caddyconfig.Warning - matcherDefs map[string]caddy.ModuleMap - parentBlock caddyfile.ServerBlock + options map[string]interface{} + warnings *[]caddyconfig.Warning + matcherDefs map[string]caddy.ModuleMap + parentBlock caddyfile.ServerBlock + groupCounter *int } // Option gets the option keyed by name. @@ -166,6 +168,32 @@ func (h Helper) NewRoute(matcherSet caddy.ModuleMap, } } +func (h Helper) GroupRoutes(vals []ConfigValue) { + // ensure there's at least two routes; group of one is pointless + var count int + for _, v := range vals { + if _, ok := v.Value.(caddyhttp.Route); ok { + count++ + if count > 1 { + break + } + } + } + if count < 2 { + return + } + + // now that we know the group will have some effect, do it + groupNum := *h.groupCounter + for i := 0; i < len(vals); i++ { + if route, ok := vals[i].Value.(caddyhttp.Route); ok { + route.Group = fmt.Sprintf("group%d", groupNum) + vals[i].Value = route + } + } + *h.groupCounter++ +} + // NewBindAddresses returns config values relevant to adding // listener bind addresses to the config. func (h Helper) NewBindAddresses(addrs []string) []ConfigValue { diff --git a/caddyconfig/httpcaddyfile/httptype.go b/caddyconfig/httpcaddyfile/httptype.go index e2035d77..257e7be3 100644 --- a/caddyconfig/httpcaddyfile/httptype.go +++ b/caddyconfig/httpcaddyfile/httptype.go @@ -41,6 +41,7 @@ type ServerType struct { func (st ServerType) Setup(originalServerBlocks []caddyfile.ServerBlock, options map[string]interface{}) (*caddy.Config, []caddyconfig.Warning, error) { var warnings []caddyconfig.Warning + groupCounter := new(int) var serverBlocks []serverBlock for _, sblock := range originalServerBlocks { @@ -140,11 +141,12 @@ func (st ServerType) Setup(originalServerBlocks []caddyfile.ServerBlock, } results, err := dirFunc(Helper{ - Dispenser: caddyfile.NewDispenser(segment), - options: options, - warnings: &warnings, - matcherDefs: matcherDefs, - parentBlock: sb.block, + Dispenser: caddyfile.NewDispenser(segment), + options: options, + warnings: &warnings, + matcherDefs: matcherDefs, + parentBlock: sb.block, + groupCounter: groupCounter, }) if err != nil { return nil, warnings, fmt.Errorf("parsing caddyfile tokens for '%s': %v", dir, err) diff --git a/modules/caddyhttp/fileserver/caddyfile.go b/modules/caddyhttp/fileserver/caddyfile.go index d26b4351..67ae4f4f 100644 --- a/modules/caddyhttp/fileserver/caddyfile.go +++ b/modules/caddyhttp/fileserver/caddyfile.go @@ -163,5 +163,10 @@ func parseTryFiles(h httpcaddyfile.Helper) ([]httpcaddyfile.ConfigValue, error) result = append(result, makeRoute(try, "")...) } + // ensure that multiple routes (possible if rewrite targets + // have query strings, for example) are grouped together + // so only the first matching rewrite is performed (#2891) + h.GroupRoutes(result) + return result, nil }