github.com/xraypb/Xray-core@v1.8.1/common/strmatcher/strmatcher.go (about) 1 package strmatcher 2 3 import ( 4 "regexp" 5 ) 6 7 // Matcher is the interface to determine a string matches a pattern. 8 type Matcher interface { 9 // Match returns true if the given string matches a predefined pattern. 10 Match(string) bool 11 String() string 12 } 13 14 // Type is the type of the matcher. 15 type Type byte 16 17 const ( 18 // Full is the type of matcher that the input string must exactly equal to the pattern. 19 Full Type = iota 20 // Substr is the type of matcher that the input string must contain the pattern as a sub-string. 21 Substr 22 // Domain is the type of matcher that the input string must be a sub-domain or itself of the pattern. 23 Domain 24 // Regex is the type of matcher that the input string must matches the regular-expression pattern. 25 Regex 26 ) 27 28 // New creates a new Matcher based on the given pattern. 29 func (t Type) New(pattern string) (Matcher, error) { 30 // 1. regex matching is case-sensitive 31 switch t { 32 case Full: 33 return fullMatcher(pattern), nil 34 case Substr: 35 return substrMatcher(pattern), nil 36 case Domain: 37 return domainMatcher(pattern), nil 38 case Regex: 39 r, err := regexp.Compile(pattern) 40 if err != nil { 41 return nil, err 42 } 43 return ®exMatcher{ 44 pattern: r, 45 }, nil 46 default: 47 panic("Unknown type") 48 } 49 } 50 51 // IndexMatcher is the interface for matching with a group of matchers. 52 type IndexMatcher interface { 53 // Match returns the index of a matcher that matches the input. It returns empty array if no such matcher exists. 54 Match(input string) []uint32 55 } 56 57 type matcherEntry struct { 58 m Matcher 59 id uint32 60 } 61 62 // MatcherGroup is an implementation of IndexMatcher. 63 // Empty initialization works. 64 type MatcherGroup struct { 65 count uint32 66 fullMatcher FullMatcherGroup 67 domainMatcher DomainMatcherGroup 68 otherMatchers []matcherEntry 69 } 70 71 // Add adds a new Matcher into the MatcherGroup, and returns its index. The index will never be 0. 72 func (g *MatcherGroup) Add(m Matcher) uint32 { 73 g.count++ 74 c := g.count 75 76 switch tm := m.(type) { 77 case fullMatcher: 78 g.fullMatcher.addMatcher(tm, c) 79 case domainMatcher: 80 g.domainMatcher.addMatcher(tm, c) 81 default: 82 g.otherMatchers = append(g.otherMatchers, matcherEntry{ 83 m: m, 84 id: c, 85 }) 86 } 87 88 return c 89 } 90 91 // Match implements IndexMatcher.Match. 92 func (g *MatcherGroup) Match(pattern string) []uint32 { 93 result := []uint32{} 94 result = append(result, g.fullMatcher.Match(pattern)...) 95 result = append(result, g.domainMatcher.Match(pattern)...) 96 for _, e := range g.otherMatchers { 97 if e.m.Match(pattern) { 98 result = append(result, e.id) 99 } 100 } 101 return result 102 } 103 104 // Size returns the number of matchers in the MatcherGroup. 105 func (g *MatcherGroup) Size() uint32 { 106 return g.count 107 }