@marcel91200 / caddy Mirror · read-only / commits / 754fe4f7
Fork 0

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")