@marcel91200 / caddy Mirror · read-only / commits / f4500684
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 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