Fast and extensible multi-platform HTTP/1-2-3 web server with automatic HTTPS
Mirrored from https://github.com/Slazee/caddy.git
Synced Nov 11, 08:30 UTC
http: normalize method names to uppercase in MatchMethod.Provision (#7832)
Signed-off-by: yintaisha <yintaishan@outlook.com>
yintaisha committed
Jun 21, 2026 at 16:19 UTC
f4500684603fb4052b0928c107c98c726a401d00
2 files changed
+64
modules/caddyhttp/matchers.go
+11
@@ -785,6 +785,15 @@ func (MatchMethod) CaddyModule() caddy.ModuleInfo {
785
}
786
}
787
788
+// Provision uppercases all configured methods to ensure case-insensitive
789
+// matching against incoming requests, whose methods are always uppercase.
790
+func (m MatchMethod) Provision(_ caddy.Context) error {
791
+ for i := range m {
792
+ m[i] = strings.ToUpper(m[i])
793
+ }
794
+ return nil
795
+}
796
+
797
// UnmarshalCaddyfile implements caddyfile.Unmarshaler.
798
func (m *MatchMethod) UnmarshalCaddyfile(d *caddyfile.Dispenser) error {
799
// iterate to merge multiple matchers into one
@@ -1645,9 +1654,11 @@ var (
1654
_ RequestMatcherWithError = (*MatchHost)(nil)
1655
_ caddy.Provisioner = (*MatchHost)(nil)
1656
_ RequestMatcherWithError = (*MatchPath)(nil)
1657
+ _ caddy.Provisioner = (*MatchPath)(nil)
1658
_ RequestMatcherWithError = (*MatchPathRE)(nil)
1659
_ caddy.Provisioner = (*MatchPathRE)(nil)
1660
_ RequestMatcherWithError = (*MatchMethod)(nil)
1661
+ _ caddy.Provisioner = (*MatchMethod)(nil)
1662
_ RequestMatcherWithError = (*MatchQuery)(nil)
1663
_ RequestMatcherWithError = (*MatchHeader)(nil)
1664
_ RequestMatcherWithError = (*MatchHeaderRE)(nil)
modules/caddyhttp/matchers_test.go
+53
@@ -1218,6 +1218,59 @@ func TestNotMatcher(t *testing.T) {
1218
}
1219
}
1220
1221
+func TestMethodMatcher(t *testing.T) {
1222
+ for i, tc := range []struct {
1223
+ scenario string
1224
+ match MatchMethod
1225
+ input string
1226
+ expect bool
1227
+ }{
1228
+ {
1229
+ scenario: "match uppercase GET",
1230
+ match: MatchMethod{"GET"},
1231
+ input: http.MethodGet,
1232
+ expect: true,
1233
+ },
1234
+ {
1235
+ scenario: "match lowercase get after Provision uppercases it",
1236
+ match: MatchMethod{"get"},
1237
+ input: http.MethodGet,
1238
+ expect: true,
1239
+ },
1240
+ {
1241
+ scenario: "match mixed case Post after Provision uppercases it",
1242
+ match: MatchMethod{"Post"},
1243
+ input: http.MethodPost,
1244
+ expect: true,
1245
+ },
1246
+ {
1247
+ scenario: "no match for wrong method",
1248
+ match: MatchMethod{"GET"},
1249
+ input: http.MethodPost,
1250
+ expect: false,
1251
+ },
1252
+ {
1253
+ scenario: "match one of multiple methods",
1254
+ match: MatchMethod{"get", "post"},
1255
+ input: http.MethodPost,
1256
+ expect: true,
1257
+ },
1258
+ } {
1259
+ req := &http.Request{Method: tc.input}
1260
+ if err := tc.match.Provision(caddy.Context{}); err != nil {
1261
+ t.Errorf("Test %d %v: provisioning failed: %v", i, tc.scenario, err)
1262
+ }
1263
+ actual, err := tc.match.MatchWithError(req)
1264
+ if err != nil {
1265
+ t.Errorf("Test %d %v: matching failed: %v", i, tc.scenario, err)
1266
+ }
1267
+ if actual != tc.expect {
1268
+ t.Errorf("Test %d %v: Expected %t, got %t for method=%s", i, tc.scenario, tc.expect, actual, tc.input)
1269
+ continue
1270
+ }
1271
+ }
1272
+}
1273
+
1274
func BenchmarkLargeHostMatcher(b *testing.B) {
1275
// this benchmark simulates a large host matcher (thousands of entries) where each
1276
// value is an exact hostname (not a placeholder or wildcard) - compare the results