1
0
Fork 0
traefik/pkg/muxer/http/parser.go
2025-05-26 17:12:08 +02:00

103 lines
2.1 KiB
Go

package http
import (
"errors"
"fmt"
"maps"
"slices"
"strings"
"github.com/traefik/traefik/v3/pkg/rules"
"github.com/vulcand/predicate"
)
type SyntaxParser struct {
parsers map[string]*parser
}
type Options func(map[string]matcherBuilderFuncs)
func WithMatcher(syntax, matcherName string, builderFunc func(params ...string) (MatcherFunc, error)) Options {
return func(syntaxFuncs map[string]matcherBuilderFuncs) {
syntax = strings.ToLower(syntax)
syntaxFuncs[syntax][matcherName] = func(tree *matchersTree, s ...string) error {
matcher, err := builderFunc(s...)
if err != nil {
return fmt.Errorf("building matcher: %w", err)
}
tree.matcher = matcher
return nil
}
}
}
func NewSyntaxParser(opts ...Options) (SyntaxParser, error) {
syntaxFuncs := map[string]matcherBuilderFuncs{
"v2": httpFuncsV2,
"v3": httpFuncs,
}
for _, opt := range opts {
opt(syntaxFuncs)
}
parsers := map[string]*parser{}
for syntax, funcs := range syntaxFuncs {
var err error
parsers[syntax], err = newParser(funcs)
if err != nil {
return SyntaxParser{}, err
}
}
return SyntaxParser{
parsers: parsers,
}, nil
}
func (s SyntaxParser) parse(syntax string, rule string) (matchersTree, error) {
parser, ok := s.parsers[syntax]
if !ok {
parser = s.parsers["v3"]
}
return parser.parse(rule)
}
func newParser(funcs matcherBuilderFuncs) (*parser, error) {
p, err := rules.NewParser(slices.Collect(maps.Keys(funcs)))
if err != nil {
return nil, err
}
return &parser{
parser: p,
matcherFuncs: funcs,
}, nil
}
type parser struct {
parser predicate.Parser
matcherFuncs matcherBuilderFuncs
}
func (p *parser) parse(rule string) (matchersTree, error) {
parse, err := p.parser.Parse(rule)
if err != nil {
return matchersTree{}, fmt.Errorf("parsing rule %s: %w", rule, err)
}
buildTree, ok := parse.(rules.TreeBuilder)
if !ok {
return matchersTree{}, errors.New("obtaining build tree")
}
var matchers matchersTree
err = matchers.addRule(buildTree(), p.matcherFuncs)
if err != nil {
return matchersTree{}, fmt.Errorf("adding rule %s: %w", rule, err)
}
return matchers, nil
}