httpcaddyfile: fix incorrect error message on duplicate matchers (#7780)

Parse each matcher segment individually using NewDispenser(segment) instead
of DispenseDirective(dir), which coalesced all same-name segments into one
token stream. This caused the second definition name to be misinterpreted
as a matcher module name, producing 'module not registered: http.matchers.@name'
instead of the correct 'matcher is defined more than once' error.

By parsing segments individually, the existing duplicate check in
parseMatcherDefinitions naturally catches the duplicate on the second pass.

Signed-off-by: Brunotlps <brunoteixlps@gmail.com>
This commit is contained in:
Bruno Teixeira Lopes
2026-05-29 18:05:41 -03:00
committed by GitHub
parent 3eb8e48ff0
commit 0e8eb41b87
2 changed files with 40 additions and 3 deletions

View File

@@ -108,7 +108,7 @@ func (st ServerType) Setup(
matcherDefs := make(map[string]caddy.ModuleMap)
for _, segment := range sb.block.Segments {
if dir := segment.Directive(); strings.HasPrefix(dir, matcherPrefix) {
d := sb.block.DispenseDirective(dir)
d := caddyfile.NewDispenser(segment)
err := parseMatcherDefinitions(d, matcherDefs)
if err != nil {
return nil, warnings, err

View File

@@ -2,6 +2,7 @@ package httpcaddyfile
import (
"encoding/json"
"strings"
"testing"
"github.com/caddyserver/caddy/v2/caddyconfig/caddyfile"
@@ -10,8 +11,9 @@ import (
func TestMatcherSyntax(t *testing.T) {
for i, tc := range []struct {
input string
expectError bool
input string
expectError bool
expectContains string
}{
{
input: `http://localhost
@@ -53,6 +55,34 @@ func TestMatcherSyntax(t *testing.T) {
`,
expectError: false,
},
{
input: `http://localhost {
@test {
path /test
}
@test {
path /other
}
respond @test "hello"
}
`,
expectError: true,
expectContains: "is defined more than once",
},
{
input: `(snippet) {
@{args[0]} {
path /{args[0]}
}
respond @{args[0]} "hello"
}
http://localhost {
import snippet foo
import snippet bar
}
`,
expectError: false,
},
{
input: `@matcher {
path /matcher-not-allowed/outside-of-site-block/*
@@ -73,6 +103,13 @@ func TestMatcherSyntax(t *testing.T) {
t.Errorf("Test %d error expectation failed Expected: %v, got %s", i, tc.expectError, err)
continue
}
if err != nil && tc.expectContains != "" {
if !strings.Contains(err.Error(), tc.expectContains) {
t.Errorf("Test %d error message mismatch: expected to contain %q, got %q",
i, tc.expectContains, err.Error())
}
}
}
}