Fast and extensible multi-platform HTTP/1-2-3 web server with automatic HTTPS
Mirrored from https://github.com/Slazee/caddy.git
Synced Nov 13, 13:00 UTC
httpcaddyfile: Fix sorting of repeated directives
Fixes #5037
Matthew Holt committed
Sep 13, 2022 at 13:43 UTC
754fe4f7b4dddbfc7a8ee7fee405cee057da858e
4 files changed
+49
-20
caddyconfig/httpcaddyfile/directives.go
+25
-18
@@ -406,7 +406,7 @@ func sortRoutes(routes []ConfigValue) {
406
return false
407
}
408
409
- // decode the path matchers, if there is just one of them
409
+ // decode the path matchers if there is just one matcher set
410
var iPM, jPM caddyhttp.MatchPath
411
if len(iRoute.MatcherSetsRaw) == 1 {
412
_ = json.Unmarshal(iRoute.MatcherSetsRaw[0]["path"], &iPM)
@@ -415,38 +415,45 @@ func sortRoutes(routes []ConfigValue) {
415
_ = json.Unmarshal(jRoute.MatcherSetsRaw[0]["path"], &jPM)
416
}
417
418
- // sort by longer path (more specific) first; missing path
419
- // matchers or multi-matchers are treated as zero-length paths
418
+ // if there is only one path in the path matcher, sort by longer path
419
+ // (more specific) first; missing path matchers or multi-matchers are
420
+ // treated as zero-length paths
421
var iPathLen, jPathLen int
421
- if len(iPM) > 0 {
422
+ if len(iPM) == 1 {
423
iPathLen = len(iPM[0])
424
}
424
- if len(jPM) > 0 {
425
+ if len(jPM) == 1 {
426
jPathLen = len(jPM[0])
427
}
428
429
// some directives involve setting values which can overwrite
429
- // eachother, so it makes most sense to reverse the order so
430
+ // each other, so it makes most sense to reverse the order so
431
// that the lease specific matcher is first; everything else
432
// has most-specific matcher first
433
if iDir == "vars" {
433
- // if both directives have no path matcher, use whichever one
434
- // has no matcher first.
435
- if iPathLen == 0 && jPathLen == 0 {
436
- return len(iRoute.MatcherSetsRaw) == 0 && len(jRoute.MatcherSetsRaw) > 0
434
+ // we can only confidently compare path lengths if both
435
+ // directives have a single path to match (issue #5037)
436
+ if iPathLen > 0 && jPathLen > 0 {
437
+ // sort least-specific (shortest) path first
438
+ return iPathLen < jPathLen
439
}
440
439
- // sort with the least-specific (shortest) path first
440
- return iPathLen < jPathLen
441
+ // if both directives don't have a single path to compare,
442
+ // sort whichever one has no matcher first; if both have
443
+ // no matcher, sort equally (stable sort preserves order)
444
+ return len(iRoute.MatcherSetsRaw) == 0 && len(jRoute.MatcherSetsRaw) > 0
445
} else {
442
- // if both directives have no path matcher, use whichever one
443
- // has any kind of matcher defined first.
444
- if iPathLen == 0 && jPathLen == 0 {
445
- return len(iRoute.MatcherSetsRaw) > 0 && len(jRoute.MatcherSetsRaw) == 0
446
+ // we can only confidently compare path lengths if both
447
+ // directives have a single path to match (issue #5037)
448
+ if iPathLen > 0 && jPathLen > 0 {
449
+ // sort most-specific (longest) path first
450
+ return iPathLen > jPathLen
451
}
452
448
- // sort with the most-specific (longest) path first
449
- return iPathLen > jPathLen
453
+ // if both directives don't have a single path to compare,
454
+ // sort whichever one has a matcher first; if both have
455
+ // a matcher, sort equally (stable sort preserves order)
456
+ return len(iRoute.MatcherSetsRaw) > 0 && len(jRoute.MatcherSetsRaw) == 0
457
}
458
})
459
}
caddyconfig/httpcaddyfile/httptype.go
+1
-1
@@ -955,7 +955,7 @@ func appendSubrouteToRouteList(routeList caddyhttp.RouteList,
955
func buildSubroute(routes []ConfigValue, groupCounter counter) (*caddyhttp.Subroute, error) {
956
for _, val := range routes {
957
if !directiveIsOrdered(val.directive) {
958
- return nil, fmt.Errorf("directive '%s' is not ordered, so it cannot be used here", val.directive)
958
+ return nil, fmt.Errorf("directive '%s' is not an ordered HTTP handler, so it cannot be used here", val.directive)
959
}
960
}
961
caddytest/caddytest.go
+1
-1
@@ -100,7 +100,7 @@ func (tc *Tester) InitServer(rawConfig string, configType string) {
100
tc.t.Fail()
101
}
102
if err := tc.ensureConfigRunning(rawConfig, configType); err != nil {
103
- tc.t.Logf("failed ensurng config is running: %s", err)
103
+ tc.t.Logf("failed ensuring config is running: %s", err)
104
tc.t.Fail()
105
}
106
}
modules/caddyhttp/routes.go
+22
@@ -109,6 +109,17 @@ func (r Route) Empty() bool {
109
r.Group == ""
110
}
111
112
+func (r Route) String() string {
113
+ handlersRaw := "["
114
+ for _, hr := range r.HandlersRaw {
115
+ handlersRaw += " " + string(hr)
116
+ }
117
+ handlersRaw += "]"
118
+
119
+ return fmt.Sprintf(`{Group:"%s" MatcherSetsRaw:%s HandlersRaw:%s Terminal:%t}`,
120
+ r.Group, r.MatcherSetsRaw, handlersRaw, r.Terminal)
121
+}
122
+
123
// RouteList is a list of server routes that can
124
// create a middleware chain.
125
type RouteList []Route
@@ -331,4 +342,15 @@ func (ms *MatcherSets) FromInterface(matcherSets any) error {
342
return nil
343
}
344
345
+// TODO: Is this used?
346
+func (ms MatcherSets) String() string {
347
+ result := "["
348
+ for _, matcherSet := range ms {
349
+ for _, matcher := range matcherSet {
350
+ result += fmt.Sprintf(" %#v", matcher)
351
+ }
352
+ }
353
+ return result + " ]"
354
+}
355
+
356
var routeGroupCtxKey = caddy.CtxKey("route_group")