Fast and extensible multi-platform HTTP/1-2-3 web server with automatic HTTPS
Mirrored from https://github.com/Slazee/caddy.git
Synced Nov 14, 05:15 UTC
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.
Matthew Holt committed
May 6, 2020 at 19:41 UTC
cd9317e5df6210c0530dd30ffc817dc07f9c7c0c
1 file changed
+33
-41
caddyconfig/httpcaddyfile/directives.go
+33
-41
@@ -276,53 +276,45 @@ func sortRoutes(routes []ConfigValue) {
276
dirPositions[dir] = i
277
}
278
279
- // while we are sorting, we will need to decode a route's path matcher
280
- // in order to sub-sort by path length; we can amortize this operation
281
- // for efficiency by storing the decoded matchers in a slice
282
- decodedMatchers := make([]caddyhttp.MatchPath, len(routes))
283
-
279
sort.SliceStable(routes, func(i, j int) bool {
280
+ // if the directives are different, just use the established directive order
281
iDir, jDir := routes[i].directive, routes[j].directive
286
- if iDir == jDir {
287
- // directives are the same; sub-sort by path matcher length
288
- // if there's only one matcher set and one path (common case)
289
- iRoute, ok := routes[i].Value.(caddyhttp.Route)
290
- if !ok {
291
- return false
292
- }
293
- jRoute, ok := routes[j].Value.(caddyhttp.Route)
294
- if !ok {
295
- return false
296
- }
282
+ if iDir != jDir {
283
+ return dirPositions[iDir] < dirPositions[jDir]
284
+ }
285
298
- // use already-decoded matcher, or decode if it's the first time seeing it
299
- iPM, jPM := decodedMatchers[i], decodedMatchers[j]
300
- if iPM == nil && len(iRoute.MatcherSetsRaw) == 1 {
301
- var pathMatcher caddyhttp.MatchPath
302
- _ = json.Unmarshal(iRoute.MatcherSetsRaw[0]["path"], &pathMatcher)
303
- decodedMatchers[i] = pathMatcher
304
- iPM = pathMatcher
305
- }
306
- if jPM == nil && len(jRoute.MatcherSetsRaw) == 1 {
307
- var pathMatcher caddyhttp.MatchPath
308
- _ = json.Unmarshal(jRoute.MatcherSetsRaw[0]["path"], &pathMatcher)
309
- decodedMatchers[j] = pathMatcher
310
- jPM = pathMatcher
311
- }
286
+ // directives are the same; sub-sort by path matcher length if there's
287
+ // only one matcher set and one path (this is a very common case and
288
+ // usually -- but not always -- helpful/expected, oh well; user can
289
+ // always take manual control of order using handler or route blocks)
290
+ iRoute, ok := routes[i].Value.(caddyhttp.Route)
291
+ if !ok {
292
+ return false
293
+ }
294
+ jRoute, ok := routes[j].Value.(caddyhttp.Route)
295
+ if !ok {
296
+ return false
297
+ }
298
313
- // sort by longer path (more specific) first; missing
314
- // path matchers are treated as zero-length paths
315
- var iPathLen, jPathLen int
316
- if iPM != nil {
317
- iPathLen = len(iPM[0])
318
- }
319
- if jPM != nil {
320
- jPathLen = len(jPM[0])
321
- }
322
- return iPathLen > jPathLen
299
+ // decode the path matchers, if there is just one of them
300
+ var iPM, jPM caddyhttp.MatchPath
301
+ if len(iRoute.MatcherSetsRaw) == 1 {
302
+ _ = json.Unmarshal(iRoute.MatcherSetsRaw[0]["path"], &iPM)
303
+ }
304
+ if len(jRoute.MatcherSetsRaw) == 1 {
305
+ _ = json.Unmarshal(jRoute.MatcherSetsRaw[0]["path"], &jPM)
306
}
307
325
- return dirPositions[iDir] < dirPositions[jDir]
308
+ // sort by longer path (more specific) first; missing path
309
+ // matchers or multi-matchers are treated as zero-length paths
310
+ var iPathLen, jPathLen int
311
+ if len(iPM) > 0 {
312
+ iPathLen = len(iPM[0])
313
+ }
314
+ if len(jPM) > 0 {
315
+ jPathLen = len(jPM[0])
316
+ }
317
+ return iPathLen > jPathLen
318
})
319
}
320