summaryrefslogtreecommitdiff
path: root/caddyconfig/httpcaddyfile
diff options
context:
space:
mode:
authorMatthew Holt <mholt@users.noreply.github.com>2020-05-06 19:41:37 -0600
committerMatthew Holt <mholt@users.noreply.github.com>2020-05-06 19:41:37 -0600
commitcd9317e5df6210c0530dd30ffc817dc07f9c7c0c (patch)
treecb4459787c8ae5ba92713b28475a1d31ded5efe8 /caddyconfig/httpcaddyfile
parent8dbc5f70a51aa17fa1ec9c2a34361d0b5d3ccae5 (diff)
httpcaddyfile: Fix route ordering bug
https://caddy.community/t/cant-get-simple-alias-to-work/7911/8?u=matt This removes an optimization where we amortized path matcher decoding. The decoded matchers were index by... position... which obviously changes during sorting. Duh. Anyway, sorting is sliiightly slower now but the Caddyfile is not really CPU-sensitive, so this is fine.
Diffstat (limited to 'caddyconfig/httpcaddyfile')
-rw-r--r--caddyconfig/httpcaddyfile/directives.go74
1 files changed, 33 insertions, 41 deletions
diff --git a/caddyconfig/httpcaddyfile/directives.go b/caddyconfig/httpcaddyfile/directives.go
index ff248bf..ac401e1 100644
--- a/caddyconfig/httpcaddyfile/directives.go
+++ b/caddyconfig/httpcaddyfile/directives.go
@@ -276,53 +276,45 @@ func sortRoutes(routes []ConfigValue) {
dirPositions[dir] = i
}
- // while we are sorting, we will need to decode a route's path matcher
- // in order to sub-sort by path length; we can amortize this operation
- // for efficiency by storing the decoded matchers in a slice
- decodedMatchers := make([]caddyhttp.MatchPath, len(routes))
-
sort.SliceStable(routes, func(i, j int) bool {
+ // if the directives are different, just use the established directive order
iDir, jDir := routes[i].directive, routes[j].directive
- if iDir == jDir {
- // directives are the same; sub-sort by path matcher length
- // if there's only one matcher set and one path (common case)
- iRoute, ok := routes[i].Value.(caddyhttp.Route)
- if !ok {
- return false
- }
- jRoute, ok := routes[j].Value.(caddyhttp.Route)
- if !ok {
- return false
- }
+ if iDir != jDir {
+ return dirPositions[iDir] < dirPositions[jDir]
+ }
- // use already-decoded matcher, or decode if it's the first time seeing it
- iPM, jPM := decodedMatchers[i], decodedMatchers[j]
- if iPM == nil && len(iRoute.MatcherSetsRaw) == 1 {
- var pathMatcher caddyhttp.MatchPath
- _ = json.Unmarshal(iRoute.MatcherSetsRaw[0]["path"], &pathMatcher)
- decodedMatchers[i] = pathMatcher
- iPM = pathMatcher
- }
- if jPM == nil && len(jRoute.MatcherSetsRaw) == 1 {
- var pathMatcher caddyhttp.MatchPath
- _ = json.Unmarshal(jRoute.MatcherSetsRaw[0]["path"], &pathMatcher)
- decodedMatchers[j] = pathMatcher
- jPM = pathMatcher
- }
+ // directives are the same; sub-sort by path matcher length if there's
+ // only one matcher set and one path (this is a very common case and
+ // usually -- but not always -- helpful/expected, oh well; user can
+ // always take manual control of order using handler or route blocks)
+ iRoute, ok := routes[i].Value.(caddyhttp.Route)
+ if !ok {
+ return false
+ }
+ jRoute, ok := routes[j].Value.(caddyhttp.Route)
+ if !ok {
+ return false
+ }
- // sort by longer path (more specific) first; missing
- // path matchers are treated as zero-length paths
- var iPathLen, jPathLen int
- if iPM != nil {
- iPathLen = len(iPM[0])
- }
- if jPM != nil {
- jPathLen = len(jPM[0])
- }
- return iPathLen > jPathLen
+ // decode the path matchers, if there is just one of them
+ var iPM, jPM caddyhttp.MatchPath
+ if len(iRoute.MatcherSetsRaw) == 1 {
+ _ = json.Unmarshal(iRoute.MatcherSetsRaw[0]["path"], &iPM)
+ }
+ if len(jRoute.MatcherSetsRaw) == 1 {
+ _ = json.Unmarshal(jRoute.MatcherSetsRaw[0]["path"], &jPM)
}
- return dirPositions[iDir] < dirPositions[jDir]
+ // sort by longer path (more specific) first; missing path
+ // matchers or multi-matchers are treated as zero-length paths
+ var iPathLen, jPathLen int
+ if len(iPM) > 0 {
+ iPathLen = len(iPM[0])
+ }
+ if len(jPM) > 0 {
+ jPathLen = len(jPM[0])
+ }
+ return iPathLen > jPathLen
})
}