155 lines
3.3 KiB
Go
155 lines
3.3 KiB
Go
package route
|
|
|
|
import (
|
|
"fmt"
|
|
"net/http"
|
|
"regexp"
|
|
"strings"
|
|
)
|
|
|
|
type matcher interface {
|
|
match(*http.Request) *match
|
|
setMatch(match *match)
|
|
|
|
canMerge(matcher) bool
|
|
merge(matcher) (matcher, error)
|
|
|
|
canChain(matcher) bool
|
|
chain(matcher) (matcher, error)
|
|
}
|
|
|
|
func hostTrieMatcher(hostname string) (matcher, error) {
|
|
return newTrieMatcher(strings.ToLower(hostname), &hostMapper{}, &match{})
|
|
}
|
|
|
|
func hostRegexpMatcher(hostname string) (matcher, error) {
|
|
return newRegexpMatcher(strings.ToLower(hostname), &hostMapper{}, &match{})
|
|
}
|
|
|
|
func methodTrieMatcher(method string) (matcher, error) {
|
|
return newTrieMatcher(method, &methodMapper{}, &match{})
|
|
}
|
|
|
|
func methodRegexpMatcher(method string) (matcher, error) {
|
|
return newRegexpMatcher(method, &methodMapper{}, &match{})
|
|
}
|
|
|
|
func pathTrieMatcher(path string) (matcher, error) {
|
|
return newTrieMatcher(path, &pathMapper{}, &match{})
|
|
}
|
|
|
|
func pathRegexpMatcher(path string) (matcher, error) {
|
|
return newRegexpMatcher(path, &pathMapper{}, &match{})
|
|
}
|
|
|
|
func headerTrieMatcher(name, value string) (matcher, error) {
|
|
return newTrieMatcher(value, &headerMapper{header: name}, &match{})
|
|
}
|
|
|
|
func headerRegexpMatcher(name, value string) (matcher, error) {
|
|
return newRegexpMatcher(value, &headerMapper{header: name}, &match{})
|
|
}
|
|
|
|
type match struct {
|
|
val interface{}
|
|
}
|
|
|
|
type andMatcher struct {
|
|
a matcher
|
|
b matcher
|
|
}
|
|
|
|
func newAndMatcher(a, b matcher) matcher {
|
|
if a.canChain(b) {
|
|
m, err := a.chain(b)
|
|
if err == nil {
|
|
return m
|
|
}
|
|
}
|
|
return &andMatcher{
|
|
a: a, b: b,
|
|
}
|
|
}
|
|
|
|
func (a *andMatcher) canChain(matcher) bool {
|
|
return false
|
|
}
|
|
|
|
func (a *andMatcher) chain(matcher) (matcher, error) {
|
|
return nil, fmt.Errorf("not supported")
|
|
}
|
|
|
|
func (a *andMatcher) String() string {
|
|
return fmt.Sprintf("andMatcher(%v, %v)", a.a, a.b)
|
|
}
|
|
|
|
func (a *andMatcher) setMatch(m *match) {
|
|
a.a.setMatch(m)
|
|
a.b.setMatch(m)
|
|
}
|
|
|
|
func (a *andMatcher) canMerge(o matcher) bool {
|
|
return false
|
|
}
|
|
|
|
func (a *andMatcher) merge(o matcher) (matcher, error) {
|
|
return nil, fmt.Errorf("Method not supported")
|
|
}
|
|
|
|
func (a *andMatcher) match(req *http.Request) *match {
|
|
result := a.a.match(req)
|
|
if result == nil {
|
|
return nil
|
|
}
|
|
return a.b.match(req)
|
|
}
|
|
|
|
// Regular expression matcher, takes a regular expression and requestMapper
|
|
type regexpMatcher struct {
|
|
// Uses this mapper to extract a string from a request to match against
|
|
mapper requestMapper
|
|
// Compiled regular expression
|
|
expr *regexp.Regexp
|
|
// match result
|
|
result *match
|
|
}
|
|
|
|
func (r *regexpMatcher) canChain(matcher) bool {
|
|
return false
|
|
}
|
|
|
|
func (r *regexpMatcher) chain(matcher) (matcher, error) {
|
|
return nil, fmt.Errorf("not supported")
|
|
}
|
|
|
|
func (m *regexpMatcher) String() string {
|
|
return fmt.Sprintf("regexpMatcher(%v)", m.expr)
|
|
}
|
|
|
|
func (m *regexpMatcher) setMatch(result *match) {
|
|
m.result = result
|
|
}
|
|
|
|
func newRegexpMatcher(expr string, mapper requestMapper, m *match) (matcher, error) {
|
|
r, err := regexp.Compile(expr)
|
|
|
|
if err != nil {
|
|
return nil, fmt.Errorf("Bad regular expression: %s %s", expr, err)
|
|
}
|
|
return ®expMatcher{expr: r, mapper: mapper, result: m}, nil
|
|
}
|
|
|
|
func (m *regexpMatcher) canMerge(matcher) bool {
|
|
return false
|
|
}
|
|
|
|
func (m *regexpMatcher) merge(matcher) (matcher, error) {
|
|
return nil, fmt.Errorf("Method not supported")
|
|
}
|
|
|
|
func (m *regexpMatcher) match(req *http.Request) *match {
|
|
if m.expr.MatchString(m.mapper.mapRequest(req)) {
|
|
return m.result
|
|
}
|
|
return nil
|
|
}
|