@marcel91200 / caddy Mirror · read-only / commits / ea1e94b8
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, 04:45 UTC

map: Distinguish duplicate literal and regexp inputs (#8067)

Hitanshu committed Sep 27, 2026 at 05:03 UTC ea1e94b89972b83b189cbb946352abd9acec0f8c
2 files changed +36 -3
modules/caddyhttp/map/map.go
+4 -3
@@ -94,7 +94,8 @@ func (h *Handler) Validate() error {
94 return fmt.Errorf("%d destinations != %d defaults", nDest, nDef)
95 }
96
97 - seen := make(map[string]int)
97 + seenLiterals := make(map[string]int)
98 + seenRegexps := make(map[string]int)
99 for i, m := range h.Mappings {
100 // prevent confusing/ambiguous mappings
101 if m.Input != "" && m.InputRegexp != "" {
@@ -102,9 +103,9 @@ func (h *Handler) Validate() error {
103 }
104
105 // prevent duplicate mappings
105 - input := m.Input
106 + input, seen := m.Input, seenLiterals
107 if m.InputRegexp != "" {
107 - input = m.InputRegexp
108 + input, seen = m.InputRegexp, seenRegexps
109 }
110 if prev, ok := seen[input]; ok {
111 return fmt.Errorf("mapping %d has a duplicate input '%s' previously used with mapping %d", i, input, prev)
modules/caddyhttp/map/map_test.go
+32
@@ -5,12 +5,44 @@ import (
5 "net/http"
6 "net/http/httptest"
7 "reflect"
8 + "strings"
9 "testing"
10
11 "github.com/caddyserver/caddy/v2"
12 "github.com/caddyserver/caddy/v2/modules/caddyhttp"
13 )
14
15 +func TestValidateDuplicateInputs(t *testing.T) {
16 + for _, tc := range []struct {
17 + name string
18 + first Mapping
19 + second Mapping
20 + wantErr bool
21 + }{
22 + {name: "duplicate literals", first: Mapping{Input: "/abc"}, second: Mapping{Input: "/abc"}, wantErr: true},
23 + {name: "duplicate regexps", first: Mapping{InputRegexp: "/abc"}, second: Mapping{InputRegexp: "/abc"}, wantErr: true},
24 + {name: "literal then regexp", first: Mapping{Input: "/abc"}, second: Mapping{InputRegexp: "/abc"}},
25 + {name: "regexp then literal", first: Mapping{InputRegexp: "/abc"}, second: Mapping{Input: "/abc"}},
26 + } {
27 + t.Run(tc.name, func(t *testing.T) {
28 + tc.first.Outputs = []any{"first"}
29 + tc.second.Outputs = []any{"second"}
30 + h := Handler{
31 + Destinations: []string{"{output}"},
32 + Mappings: []Mapping{tc.first, tc.second},
33 + }
34 + err := h.Validate()
35 + if tc.wantErr {
36 + if err == nil || !strings.Contains(err.Error(), "duplicate input '/abc'") {
37 + t.Fatalf("expected duplicate input error, got %v", err)
38 + }
39 + } else if err != nil {
40 + t.Fatalf("unexpected validation error: %v", err)
41 + }
42 + })
43 + }
44 +}
45 +
46 func TestHandler(t *testing.T) {
47 for i, tc := range []struct {
48 handler Handler