caddyfile: Refactor; NewFromNextSegment(); fix repeated matchers

Now multiple instances of the same matcher can be used within a named
matcher without overwriting previous ones.
This commit is contained in:
Matthew Holt 2020-02-14 11:00:16 -07:00
parent eb80165583
commit 15bf9c196c
8 changed files with 76 additions and 13 deletions

View file

@ -249,13 +249,20 @@ func (d *Dispenser) RemainingArgs() []string {
return args return args
} }
// NewFromNextTokens returns a new dispenser with a copy of // NewFromNextSegment returns a new dispenser with a copy of
// the tokens from the current token until the end of the // the tokens from the current token until the end of the
// "directive" whether that be to the end of the line or // "directive" whether that be to the end of the line or
// the end of a block that starts at the end of the line; // the end of a block that starts at the end of the line;
// in other words, until the end of the segment. // in other words, until the end of the segment.
func (d *Dispenser) NewFromNextTokens() *Dispenser { func (d *Dispenser) NewFromNextSegment() *Dispenser {
tkns := []Token{d.Token()} return NewDispenser(d.NextSegment())
}
// NextSegment returns a copy of the tokens from the current
// token until the end of the line or block that starts at
// the end of the line.
func (d *Dispenser) NextSegment() Segment {
tkns := Segment{d.Token()}
for d.NextArg() { for d.NextArg() {
tkns = append(tkns, d.Token()) tkns = append(tkns, d.Token())
} }
@ -282,7 +289,7 @@ func (d *Dispenser) NewFromNextTokens() *Dispenser {
// next iteration of the enclosing loop will // next iteration of the enclosing loop will
// call Next() and consume it // call Next() and consume it
} }
return NewDispenser(tkns) return tkns
} }
// Token returns the current token. // Token returns the current token.

View file

@ -368,7 +368,7 @@ func parseRoute(h Helper) (caddyhttp.MiddlewareHandler, error) {
} }
subHelper := h subHelper := h
subHelper.Dispenser = h.NewFromNextTokens() subHelper.Dispenser = h.NewFromNextSegment()
results, err := dirFunc(subHelper) results, err := dirFunc(subHelper)
if err != nil { if err != nil {
@ -401,7 +401,7 @@ func parseHandle(h Helper) (caddyhttp.MiddlewareHandler, error) {
} }
subHelper := h subHelper := h
subHelper.Dispenser = h.NewFromNextTokens() subHelper.Dispenser = h.NewFromNextSegment()
results, err := dirFunc(subHelper) results, err := dirFunc(subHelper)
if err != nil { if err != nil {

View file

@ -751,8 +751,16 @@ func parseMatcherDefinitions(d *caddyfile.Dispenser, matchers map[string]caddy.M
} }
matchers[definitionName] = make(caddy.ModuleMap) matchers[definitionName] = make(caddy.ModuleMap)
// 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.NextBlock(nesting); { for nesting := d.Nesting(); d.NextBlock(nesting); {
matcherName := d.Val() matcherName := d.Val()
tokensByMatcherName[matcherName] = append(tokensByMatcherName[matcherName], d.NextSegment()...)
}
for matcherName, tokens := range tokensByMatcherName {
mod, err := caddy.GetModule("http.matchers." + matcherName) mod, err := caddy.GetModule("http.matchers." + matcherName)
if err != nil { if err != nil {
return fmt.Errorf("getting matcher module '%s': %v", matcherName, err) return fmt.Errorf("getting matcher module '%s': %v", matcherName, err)
@ -761,7 +769,7 @@ func parseMatcherDefinitions(d *caddyfile.Dispenser, matchers map[string]caddy.M
if !ok { if !ok {
return fmt.Errorf("matcher module '%s' is not a Caddyfile unmarshaler", matcherName) return fmt.Errorf("matcher module '%s' is not a Caddyfile unmarshaler", matcherName)
} }
err = unm.UnmarshalCaddyfile(d.NewFromNextTokens()) err = unm.UnmarshalCaddyfile(caddyfile.NewDispenser(tokens))
if err != nil { if err != nil {
return err return err
} }

View file

@ -1,6 +1,54 @@
package httpcaddyfile package httpcaddyfile
import "testing" import (
"testing"
"github.com/caddyserver/caddy/v2/caddyconfig/caddyfile"
)
func TestServerType(t *testing.T) {
for i, tc := range []struct {
input string
expectWarn bool
expectError bool
}{
{
input: `http://localhost
@debug {
query showdebug=1
}
`,
expectWarn: false,
expectError: false,
},
{
input: `http://localhost
@debug {
query bad format
}
`,
expectWarn: false,
expectError: true,
},
} {
adapter := caddyfile.Adapter{
ServerType: ServerType{},
}
_, warnings, err := adapter.Adapt([]byte(tc.input), nil)
if len(warnings) > 0 != tc.expectWarn {
t.Errorf("Test %d warning expectation failed Expected: %v, got %v", i, tc.expectWarn, warnings)
continue
}
if err != nil != tc.expectError {
t.Errorf("Test %d error expectation failed Expected: %v, got %s", i, tc.expectError, err)
continue
}
}
}
func TestSpecificity(t *testing.T) { func TestSpecificity(t *testing.T) {
for i, tc := range []struct { for i, tc := range []struct {

View file

@ -151,7 +151,7 @@ func parseOptStorage(d *caddyfile.Dispenser) (caddy.StorageConverter, error) {
if !ok { if !ok {
return nil, fmt.Errorf("storage module '%s' is not a Caddyfile unmarshaler", mod.ID) return nil, fmt.Errorf("storage module '%s' is not a Caddyfile unmarshaler", mod.ID)
} }
err = unm.UnmarshalCaddyfile(d.NewFromNextTokens()) err = unm.UnmarshalCaddyfile(d.NewFromNextSegment())
if err != nil { if err != nil {
return nil, err return nil, err
} }

View file

@ -73,7 +73,7 @@ func (enc *Encode) UnmarshalCaddyfile(d *caddyfile.Dispenser) error {
if !ok { if !ok {
return fmt.Errorf("encoder module '%s' is not a Caddyfile unmarshaler", mod) return fmt.Errorf("encoder module '%s' is not a Caddyfile unmarshaler", mod)
} }
err = unm.UnmarshalCaddyfile(d.NewFromNextTokens()) err = unm.UnmarshalCaddyfile(d.NewFromNextSegment())
if err != nil { if err != nil {
return err return err
} }

View file

@ -520,7 +520,7 @@ func (m *MatchNegate) UnmarshalCaddyfile(d *caddyfile.Dispenser) error {
if !ok { if !ok {
return d.Errf("matcher module '%s' is not a Caddyfile unmarshaler", matcherName) return d.Errf("matcher module '%s' is not a Caddyfile unmarshaler", matcherName)
} }
err = unm.UnmarshalCaddyfile(d.NewFromNextTokens()) err = unm.UnmarshalCaddyfile(d.NewFromNextSegment())
if err != nil { if err != nil {
return err return err
} }

View file

@ -114,7 +114,7 @@ func (h *Handler) UnmarshalCaddyfile(d *caddyfile.Dispenser) error {
if !ok { if !ok {
return d.Errf("load balancing policy module '%s' is not a Caddyfile unmarshaler", mod) return d.Errf("load balancing policy module '%s' is not a Caddyfile unmarshaler", mod)
} }
err = unm.UnmarshalCaddyfile(d.NewFromNextTokens()) err = unm.UnmarshalCaddyfile(d.NewFromNextSegment())
if err != nil { if err != nil {
return err return err
} }
@ -401,7 +401,7 @@ func (h *Handler) UnmarshalCaddyfile(d *caddyfile.Dispenser) error {
if !ok { if !ok {
return d.Errf("transport module '%s' is not a Caddyfile unmarshaler", mod) return d.Errf("transport module '%s' is not a Caddyfile unmarshaler", mod)
} }
err = unm.UnmarshalCaddyfile(d.NewFromNextTokens()) err = unm.UnmarshalCaddyfile(d.NewFromNextSegment())
if err != nil { if err != nil {
return err return err
} }