2018-08-19 15:04:15 -04:00
|
|
|
package strmatcher
|
|
|
|
|
2022-09-16 02:40:03 -04:00
|
|
|
type trieNode struct {
|
|
|
|
values []uint32
|
|
|
|
children map[string]*trieNode
|
2018-08-19 15:04:15 -04:00
|
|
|
}
|
|
|
|
|
2021-10-31 06:01:13 -04:00
|
|
|
// DomainMatcherGroup is an implementation of MatcherGroup.
|
|
|
|
// It uses trie to optimize both memory consumption and lookup speed. Trie node is domain label based.
|
2018-08-19 15:04:15 -04:00
|
|
|
type DomainMatcherGroup struct {
|
2022-09-16 02:40:03 -04:00
|
|
|
root *trieNode
|
2018-08-19 15:04:15 -04:00
|
|
|
}
|
|
|
|
|
2022-09-16 02:40:03 -04:00
|
|
|
func NewDomainMatcherGroup() *DomainMatcherGroup {
|
|
|
|
return &DomainMatcherGroup{
|
|
|
|
root: new(trieNode),
|
2018-08-19 15:04:15 -04:00
|
|
|
}
|
2022-09-16 02:40:03 -04:00
|
|
|
}
|
2018-08-19 15:04:15 -04:00
|
|
|
|
2022-09-16 02:40:03 -04:00
|
|
|
// AddDomainMatcher implements MatcherGroupForDomain.AddDomainMatcher.
|
|
|
|
func (g *DomainMatcherGroup) AddDomainMatcher(matcher DomainMatcher, value uint32) {
|
|
|
|
node := g.root
|
|
|
|
pattern := matcher.Pattern()
|
|
|
|
for i := len(pattern); i > 0; {
|
|
|
|
var part string
|
|
|
|
for j := i - 1; ; j-- {
|
|
|
|
if pattern[j] == '.' {
|
|
|
|
part = pattern[j+1 : i]
|
|
|
|
i = j
|
|
|
|
break
|
|
|
|
}
|
|
|
|
if j == 0 {
|
|
|
|
part = pattern[j:i]
|
|
|
|
i = j
|
|
|
|
break
|
|
|
|
}
|
2018-08-22 16:49:02 -04:00
|
|
|
}
|
2022-09-16 02:40:03 -04:00
|
|
|
if node.children == nil {
|
|
|
|
node.children = make(map[string]*trieNode)
|
|
|
|
}
|
|
|
|
next := node.children[part]
|
2018-08-19 15:04:15 -04:00
|
|
|
if next == nil {
|
2022-09-16 02:40:03 -04:00
|
|
|
next = new(trieNode)
|
|
|
|
node.children[part] = next
|
2018-08-19 15:04:15 -04:00
|
|
|
}
|
2022-09-16 02:40:03 -04:00
|
|
|
node = next
|
2018-08-19 15:04:15 -04:00
|
|
|
}
|
|
|
|
|
2022-09-16 02:40:03 -04:00
|
|
|
node.values = append(node.values, value)
|
2018-08-19 15:04:15 -04:00
|
|
|
}
|
|
|
|
|
2021-10-31 06:01:13 -04:00
|
|
|
// Match implements MatcherGroup.Match.
|
2022-09-16 02:40:03 -04:00
|
|
|
func (g *DomainMatcherGroup) Match(input string) []uint32 {
|
|
|
|
matches := make([][]uint32, 0, 5)
|
|
|
|
node := g.root
|
|
|
|
for i := len(input); i > 0; {
|
|
|
|
for j := i - 1; ; j-- {
|
|
|
|
if input[j] == '.' { // Domain label found
|
|
|
|
node = node.children[input[j+1:i]]
|
|
|
|
i = j
|
|
|
|
break
|
|
|
|
}
|
|
|
|
if j == 0 { // The last part of domain label
|
|
|
|
node = node.children[input[j:i]]
|
|
|
|
i = j
|
|
|
|
break
|
2018-11-02 07:14:41 -04:00
|
|
|
}
|
|
|
|
}
|
2022-09-16 02:40:03 -04:00
|
|
|
if node == nil { // No more match if no trie edge transition
|
2018-08-19 15:04:15 -04:00
|
|
|
break
|
|
|
|
}
|
2022-09-16 02:40:03 -04:00
|
|
|
if len(node.values) > 0 { // Found matched matchers
|
|
|
|
matches = append(matches, node.values)
|
2020-08-13 03:26:30 -04:00
|
|
|
}
|
2022-09-16 02:40:03 -04:00
|
|
|
if node.children == nil { // No more match if leaf node reached
|
|
|
|
break
|
2020-08-13 03:26:30 -04:00
|
|
|
}
|
2018-08-19 15:04:15 -04:00
|
|
|
}
|
2022-09-16 02:40:03 -04:00
|
|
|
return CompositeMatchesReverse(matches)
|
2018-08-19 15:04:15 -04:00
|
|
|
}
|
2021-10-31 06:01:13 -04:00
|
|
|
|
|
|
|
// MatchAny implements MatcherGroup.MatchAny.
|
2022-09-16 02:40:03 -04:00
|
|
|
func (g *DomainMatcherGroup) MatchAny(input string) bool {
|
|
|
|
node := g.root
|
|
|
|
for i := len(input); i > 0; {
|
|
|
|
for j := i - 1; ; j-- {
|
|
|
|
if input[j] == '.' {
|
|
|
|
node = node.children[input[j+1:i]]
|
|
|
|
i = j
|
|
|
|
break
|
|
|
|
}
|
|
|
|
if j == 0 {
|
|
|
|
node = node.children[input[j:i]]
|
|
|
|
i = j
|
|
|
|
break
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if node == nil {
|
|
|
|
return false
|
|
|
|
}
|
|
|
|
if len(node.values) > 0 {
|
|
|
|
return true
|
|
|
|
}
|
|
|
|
if node.children == nil {
|
|
|
|
return false
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return false
|
2021-10-31 06:01:13 -04:00
|
|
|
}
|