From 8c5d00b2bc815c182e1a510be6dddc128949bf23 Mon Sep 17 00:00:00 2001 From: Francis Lavoie Date: Tue, 26 May 2020 17:27:51 -0400 Subject: httpcaddyfile: New `handle_path` directive (#3281) * caddyconfig: WIP implementation of handle_path * caddyconfig: Complete the implementation - h.NewRoute was key * caddyconfig: Add handle_path integration test * caddyhttp: Use the path matcher as-is, strip the trailing *, update test --- caddyconfig/httpcaddyfile/directives.go | 115 ++++++++++++++++---------------- 1 file changed, 58 insertions(+), 57 deletions(-) (limited to 'caddyconfig/httpcaddyfile/directives.go') diff --git a/caddyconfig/httpcaddyfile/directives.go b/caddyconfig/httpcaddyfile/directives.go index 1578772..cde9743 100644 --- a/caddyconfig/httpcaddyfile/directives.go +++ b/caddyconfig/httpcaddyfile/directives.go @@ -57,6 +57,7 @@ var directiveOrder = []string{ // special routing directives "handle", "route", + "handle_path", // handlers that typically respond to requests "respond", @@ -261,6 +262,63 @@ func (h Helper) NewBindAddresses(addrs []string) []ConfigValue { return []ConfigValue{{Class: "bind", Value: addrs}} } +// ParseSegmentAsSubroute parses the segment such that its subdirectives +// are themselves treated as directives, from which a subroute is built +// and returned. +func ParseSegmentAsSubroute(h Helper) (caddyhttp.MiddlewareHandler, error) { + var allResults []ConfigValue + + for h.Next() { + // slice the linear list of tokens into top-level segments + var segments []caddyfile.Segment + for nesting := h.Nesting(); h.NextBlock(nesting); { + segments = append(segments, h.NextSegment()) + } + + // copy existing matcher definitions so we can augment + // new ones that are defined only in this scope + matcherDefs := make(map[string]caddy.ModuleMap, len(h.matcherDefs)) + for key, val := range h.matcherDefs { + matcherDefs[key] = val + } + + // find and extract any embedded matcher definitions in this scope + for i, seg := range segments { + if strings.HasPrefix(seg.Directive(), matcherPrefix) { + err := parseMatcherDefinitions(caddyfile.NewDispenser(seg), matcherDefs) + if err != nil { + return nil, err + } + segments = append(segments[:i], segments[i+1:]...) + } + } + + // with matchers ready to go, evaluate each directive's segment + for _, seg := range segments { + dir := seg.Directive() + dirFunc, ok := registeredDirectives[dir] + if !ok { + return nil, h.Errf("unrecognized directive: %s", dir) + } + + subHelper := h + subHelper.Dispenser = caddyfile.NewDispenser(seg) + subHelper.matcherDefs = matcherDefs + + results, err := dirFunc(subHelper) + if err != nil { + return nil, h.Errf("parsing caddyfile tokens for '%s': %v", dir, err) + } + for _, result := range results { + result.directive = dir + allResults = append(allResults, result) + } + } + } + + return buildSubroute(allResults, h.groupCounter) +} + // ConfigValue represents a value to be added to the final // configuration, or a value to be consulted when building // the final configuration. @@ -329,63 +387,6 @@ func sortRoutes(routes []ConfigValue) { }) } -// parseSegmentAsSubroute parses the segment such that its subdirectives -// are themselves treated as directives, from which a subroute is built -// and returned. -func parseSegmentAsSubroute(h Helper) (caddyhttp.MiddlewareHandler, error) { - var allResults []ConfigValue - - for h.Next() { - // slice the linear list of tokens into top-level segments - var segments []caddyfile.Segment - for nesting := h.Nesting(); h.NextBlock(nesting); { - segments = append(segments, h.NextSegment()) - } - - // copy existing matcher definitions so we can augment - // new ones that are defined only in this scope - matcherDefs := make(map[string]caddy.ModuleMap, len(h.matcherDefs)) - for key, val := range h.matcherDefs { - matcherDefs[key] = val - } - - // find and extract any embedded matcher definitions in this scope - for i, seg := range segments { - if strings.HasPrefix(seg.Directive(), matcherPrefix) { - err := parseMatcherDefinitions(caddyfile.NewDispenser(seg), matcherDefs) - if err != nil { - return nil, err - } - segments = append(segments[:i], segments[i+1:]...) - } - } - - // with matchers ready to go, evaluate each directive's segment - for _, seg := range segments { - dir := seg.Directive() - dirFunc, ok := registeredDirectives[dir] - if !ok { - return nil, h.Errf("unrecognized directive: %s", dir) - } - - subHelper := h - subHelper.Dispenser = caddyfile.NewDispenser(seg) - subHelper.matcherDefs = matcherDefs - - results, err := dirFunc(subHelper) - if err != nil { - return nil, h.Errf("parsing caddyfile tokens for '%s': %v", dir, err) - } - for _, result := range results { - result.directive = dir - allResults = append(allResults, result) - } - } - } - - return buildSubroute(allResults, h.groupCounter) -} - // serverBlock pairs a Caddyfile server block with // a "pile" of config values, keyed by class name, // as well as its parsed keys for convenience. -- cgit v1.2.3