diff --git a/caddytest/integration/caddyfile_adapt_test.go b/caddytest/integration/caddyfile_adapt_test.go index f6120aef..514a5064 100644 --- a/caddytest/integration/caddyfile_adapt_test.go +++ b/caddytest/integration/caddyfile_adapt_test.go @@ -362,4 +362,56 @@ func TestMatcherSyntax(t *testing.T) { } } }`) -} \ No newline at end of file +} + +func TestNotBlockMerging(t *testing.T) { + caddytest.AssertAdapt(t, ` + :80 + + @test { + not { + header Abc "123" + header Bcd "123" + } + } + respond @test 403 + `, "caddyfile", `{ + "apps": { + "http": { + "servers": { + "srv0": { + "listen": [ + ":80" + ], + "routes": [ + { + "match": [ + { + "not": [ + { + "header": { + "Abc": [ + "123" + ], + "Bcd": [ + "123" + ] + } + } + ] + } + ], + "handle": [ + { + "handler": "static_response", + "status_code": 403 + } + ] + } + ] + } + } + } + } +}`) +} diff --git a/modules/caddyhttp/matchers.go b/modules/caddyhttp/matchers.go index 95100d58..08607803 100644 --- a/modules/caddyhttp/matchers.go +++ b/modules/caddyhttp/matchers.go @@ -592,8 +592,17 @@ func (m *MatchNot) UnmarshalCaddyfile(d *caddyfile.Dispenser) error { for d.Next() { var mp matcherPair matcherMap := make(map[string]RequestMatcher) - for d.NextArg() || d.NextBlock(0) { + + // in case there are multiple instances of the same matcher, concatenate + // their tokens (we expect that UnmarshalCaddyfile should be able to + // handle more than one segment); otherwise, we'd overwrite other + // instances of the matcher in this set + tokensByMatcherName := make(map[string][]caddyfile.Token) + for nesting := d.Nesting(); d.NextArg() || d.NextBlock(nesting); { matcherName := d.Val() + tokensByMatcherName[matcherName] = append(tokensByMatcherName[matcherName], d.NextSegment()...) + } + for matcherName, tokens := range tokensByMatcherName { mod, err := caddy.GetModule("http.matchers." + matcherName) if err != nil { return d.Errf("getting matcher module '%s': %v", matcherName, err) @@ -602,11 +611,14 @@ func (m *MatchNot) UnmarshalCaddyfile(d *caddyfile.Dispenser) error { if !ok { return d.Errf("matcher module '%s' is not a Caddyfile unmarshaler", matcherName) } - err = unm.UnmarshalCaddyfile(d.NewFromNextSegment()) + err = unm.UnmarshalCaddyfile(caddyfile.NewDispenser(tokens)) if err != nil { return err } - rm := unm.(RequestMatcher) + rm, ok := unm.(RequestMatcher) + if !ok { + return fmt.Errorf("matcher module '%s' is not a request matcher", matcherName) + } matcherMap[matcherName] = rm mp.decoded = append(mp.decoded, rm) }