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
http: Make path matcher case-insensitive
Adds tests for both the path matcher and host matcher for case insensitivity. If case sensitivity is required for the path, a regexp matcher can be used instead. This is the v2 equivalent fix of PR #2882.
Matthew Holt committed
Nov 15, 2019 at 12:47 UTC
0fc97211abd46098f5953fc6b152aa891060fca5
2 files changed
+45
-6
modules/caddyhttp/matchers.go
+14
-5
@@ -33,10 +33,10 @@ import (
33
)
34
35
type (
36
- // MatchHost matches requests by the Host value.
36
+ // MatchHost matches requests by the Host value (case-insensitive).
37
MatchHost []string
38
39
- // MatchPath matches requests by the URI's path.
39
+ // MatchPath matches requests by the URI's path (case-insensitive).
40
MatchPath []string
41
42
// MatchPathRE matches requests by a regular expression on the URI's path.
@@ -154,20 +154,29 @@ func (MatchPath) CaddyModule() caddy.ModuleInfo {
154
}
155
}
156
157
+// Provision lower-cases the paths in m to ensure case-insensitive matching.
158
+func (m MatchPath) Provision(_ caddy.Context) error {
159
+ for i := range m {
160
+ m[i] = strings.ToLower(m[i])
161
+ }
162
+ return nil
163
+}
164
+
165
// Match returns true if r matches m.
166
func (m MatchPath) Match(r *http.Request) bool {
167
+ lowerPath := strings.ToLower(r.URL.Path)
168
for _, matchPath := range m {
169
// as a special case, if the first character is a
170
// wildcard, treat it as a quick suffix match
171
if strings.HasPrefix(matchPath, "*") {
163
- return strings.HasSuffix(r.URL.Path, matchPath[1:])
172
+ return strings.HasSuffix(lowerPath, matchPath[1:])
173
}
174
// can ignore error here because we can't handle it anyway
166
- matches, _ := filepath.Match(matchPath, r.URL.Path)
175
+ matches, _ := filepath.Match(matchPath, lowerPath)
176
if matches {
177
return true
178
}
170
- if strings.HasPrefix(r.URL.Path, matchPath) {
179
+ if strings.HasPrefix(lowerPath, matchPath) {
180
return true
181
}
182
}
modules/caddyhttp/matchers_test.go
+31
-1
@@ -47,6 +47,16 @@ func TestHostMatcher(t *testing.T) {
47
input: "example.com",
48
expect: true,
49
},
50
+ {
51
+ match: MatchHost{"EXAMPLE.COM"},
52
+ input: "example.com",
53
+ expect: true,
54
+ },
55
+ {
56
+ match: MatchHost{"example.com"},
57
+ input: "EXAMPLE.COM",
58
+ expect: true,
59
+ },
60
{
61
match: MatchHost{"example.com"},
62
input: "foo.example.com",
@@ -72,6 +82,11 @@ func TestHostMatcher(t *testing.T) {
82
input: "example.com",
83
expect: false,
84
},
85
+ {
86
+ match: MatchHost{"*.example.com"},
87
+ input: "SUB.EXAMPLE.COM",
88
+ expect: true,
89
+ },
90
{
91
match: MatchHost{"*.example.com"},
92
input: "foo.example.com",
@@ -174,7 +189,12 @@ func TestPathMatcher(t *testing.T) {
189
},
190
{
191
match: MatchPath{"*.ext"},
177
- input: "foo.ext",
192
+ input: "/foo.ext",
193
+ expect: true,
194
+ },
195
+ {
196
+ match: MatchPath{"*.php"},
197
+ input: "/index.PHP",
198
expect: true,
199
},
200
{
@@ -192,6 +212,16 @@ func TestPathMatcher(t *testing.T) {
212
input: "/foo/bar/bam",
213
expect: false,
214
},
215
+ {
216
+ match: MatchPath{"/foo"},
217
+ input: "/FOO",
218
+ expect: true,
219
+ },
220
+ {
221
+ match: MatchPath{"/foo/bar.txt"},
222
+ input: "/foo/BAR.txt",
223
+ expect: true,
224
+ },
225
} {
226
req := &http.Request{URL: &url.URL{Path: tc.input}}
227
actual := tc.match.Match(req)