@marcel91200 / caddy Mirror · read-only / commits / 330be2d8
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, 05:30 UTC

httpcaddyfile: Adjust path matcher sorting to solve for specificity (#5462)

Francis Lavoie committed Mar 27, 2023 at 15:43 UTC 330be2d8c793147d3914f944eecb96c18f2eabff
4 files changed +82 -29
caddyconfig/httpcaddyfile/directives.go
+17 -16
@@ -427,26 +427,16 @@ func sortRoutes(routes []ConfigValue) {
427 jPathLen = len(jPM[0])
428 }
429
430 - // some directives involve setting values which can overwrite
431 - // each other, so it makes most sense to reverse the order so
432 - // that the lease specific matcher is first; everything else
433 - // has most-specific matcher first
434 - if iDir == "vars" {
430 + sortByPath := func() bool {
431 // we can only confidently compare path lengths if both
432 // directives have a single path to match (issue #5037)
433 if iPathLen > 0 && jPathLen > 0 {
438 - // sort least-specific (shortest) path first
439 - return iPathLen < jPathLen
440 - }
434 + // if both paths are the same except for a trailing wildcard,
435 + // sort by the shorter path first (which is more specific)
436 + if strings.TrimSuffix(iPM[0], "*") == strings.TrimSuffix(jPM[0], "*") {
437 + return iPathLen < jPathLen
438 + }
439
442 - // if both directives don't have a single path to compare,
443 - // sort whichever one has no matcher first; if both have
444 - // no matcher, sort equally (stable sort preserves order)
445 - return len(iRoute.MatcherSetsRaw) == 0 && len(jRoute.MatcherSetsRaw) > 0
446 - } else {
447 - // we can only confidently compare path lengths if both
448 - // directives have a single path to match (issue #5037)
449 - if iPathLen > 0 && jPathLen > 0 {
440 // sort most-specific (longest) path first
441 return iPathLen > jPathLen
442 }
@@ -455,7 +445,18 @@ func sortRoutes(routes []ConfigValue) {
445 // sort whichever one has a matcher first; if both have
446 // a matcher, sort equally (stable sort preserves order)
447 return len(iRoute.MatcherSetsRaw) > 0 && len(jRoute.MatcherSetsRaw) == 0
448 + }()
449 +
450 + // some directives involve setting values which can overwrite
451 + // each other, so it makes most sense to reverse the order so
452 + // that the least-specific matcher is first, allowing the last
453 + // matching one to win
454 + if iDir == "vars" {
455 + return !sortByPath
456 }
457 +
458 + // everything else is most-specific matcher first
459 + return sortByPath
460 })
461 }
462
caddytest/integration/caddyfile_adapt/map_and_vars_with_raw_types.txt
+4 -4
@@ -100,16 +100,16 @@ vars {
100 ],
101 "source": "{http.request.host}"
102 },
103 - {
104 - "foo": "bar",
105 - "handler": "vars"
106 - },
103 {
104 "abc": true,
105 "def": 1,
106 "ghi": 2.3,
107 "handler": "vars",
108 "jkl": "mn op"
109 + },
110 + {
111 + "foo": "bar",
112 + "handler": "vars"
113 }
114 ]
115 }
caddytest/integration/caddyfile_adapt/sort_directives_within_handle.txt
+43 -7
@@ -1,12 +1,15 @@
1 *.example.com {
2 @foo host foo.example.com
3 handle @foo {
4 - handle_path /strip* {
4 + handle_path /strip {
5 respond "this should be first"
6 }
7 - handle {
7 + handle_path /strip* {
8 respond "this should be second"
9 }
10 + handle {
11 + respond "this should be last"
12 + }
13 }
14 handle {
15 respond "this should be last"
@@ -35,13 +38,13 @@
38 "handler": "subroute",
39 "routes": [
40 {
38 - "group": "group5",
41 + "group": "group6",
42 "handle": [
43 {
44 "handler": "subroute",
45 "routes": [
46 {
44 - "group": "group2",
47 + "group": "group3",
48 "handle": [
49 {
50 "handler": "subroute",
@@ -68,17 +71,25 @@
71 "match": [
72 {
73 "path": [
71 - "/strip*"
74 + "/strip"
75 ]
76 }
77 ]
78 },
79 {
77 - "group": "group2",
80 + "group": "group3",
81 "handle": [
82 {
83 "handler": "subroute",
84 "routes": [
85 + {
86 + "handle": [
87 + {
88 + "handler": "rewrite",
89 + "strip_path_prefix": "/strip"
90 + }
91 + ]
92 + },
93 {
94 "handle": [
95 {
@@ -89,6 +100,31 @@
100 }
101 ]
102 }
103 + ],
104 + "match": [
105 + {
106 + "path": [
107 + "/strip*"
108 + ]
109 + }
110 + ]
111 + },
112 + {
113 + "group": "group3",
114 + "handle": [
115 + {
116 + "handler": "subroute",
117 + "routes": [
118 + {
119 + "handle": [
120 + {
121 + "body": "this should be last",
122 + "handler": "static_response"
123 + }
124 + ]
125 + }
126 + ]
127 + }
128 ]
129 }
130 ]
@@ -103,7 +139,7 @@
139 ]
140 },
141 {
106 - "group": "group5",
142 + "group": "group6",
143 "handle": [
144 {
145 "handler": "subroute",
caddytest/integration/caddyfile_adapt/sort_vars_in_reverse.txt
+18 -2
@@ -1,7 +1,8 @@
1 :80
2
3 vars /foobar foo last
4 -vars /foo foo middle
4 +vars /foo foo middle-last
5 +vars /foo* foo middle-first
6 vars * foo first
7 ----------
8 {
@@ -21,6 +22,21 @@ vars * foo first
22 }
23 ]
24 },
25 + {
26 + "match": [
27 + {
28 + "path": [
29 + "/foo*"
30 + ]
31 + }
32 + ],
33 + "handle": [
34 + {
35 + "foo": "middle-first",
36 + "handler": "vars"
37 + }
38 + ]
39 + },
40 {
41 "match": [
42 {
@@ -31,7 +47,7 @@ vars * foo first
47 ],
48 "handle": [
49 {
34 - "foo": "middle",
50 + "foo": "middle-last",
51 "handler": "vars"
52 }
53 ]