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
]