-
Notifications
You must be signed in to change notification settings - Fork 11
/
matcher.go
156 lines (124 loc) · 3.32 KB
/
matcher.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
package route
import (
"errors"
"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)
}
type match struct {
val interface{}
}
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 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(_ matcher) bool {
return false
}
func (a *andMatcher) merge(_ matcher) (matcher, error) {
return nil, errors.New("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 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 %w", expr, err)
}
return ®expMatcher{expr: r, mapper: mapper, result: m}, nil
}
func (r *regexpMatcher) canChain(matcher) bool {
return false
}
func (r *regexpMatcher) chain(matcher) (matcher, error) {
return nil, fmt.Errorf("not supported")
}
func (r *regexpMatcher) String() string {
return fmt.Sprintf("regexpMatcher(%v)", r.expr)
}
func (r *regexpMatcher) setMatch(result *match) {
r.result = result
}
func (r *regexpMatcher) canMerge(matcher) bool {
return false
}
func (r *regexpMatcher) merge(matcher) (matcher, error) {
return nil, errors.New("method not supported")
}
func (r *regexpMatcher) match(req *http.Request) *match {
if r.expr.MatchString(r.mapper.mapRequest(req)) {
return r.result
}
return nil
}