diff --git a/app/dns/hosts.go b/app/dns/hosts.go index b97ee4772..35a2b7508 100644 --- a/app/dns/hosts.go +++ b/app/dns/hosts.go @@ -17,7 +17,7 @@ var typeMap = map[Config_HostMapping_Type]strmatcher.Type{ } func NewStaticHosts(hosts []*Config_HostMapping, legacy map[string]*net.IPOrDomain) (*StaticHosts, error) { - g := strmatcher.NewMatcherGroup() + g := new(strmatcher.MatcherGroup) sh := &StaticHosts{ ips: make(map[uint32][]net.IP), matchers: g, diff --git a/app/router/condition.go b/app/router/condition.go index 5735bd4ca..36364c32d 100644 --- a/app/router/condition.go +++ b/app/router/condition.go @@ -90,7 +90,7 @@ type DomainMatcher struct { } func NewDomainMatcher(domains []*Domain) (*DomainMatcher, error) { - g := strmatcher.NewMatcherGroup() + g := new(strmatcher.MatcherGroup) for _, d := range domains { m, err := domainToMatcher(d) if err != nil { diff --git a/common/strmatcher/benchmark_test.go b/common/strmatcher/benchmark_test.go index 2915a4104..1e7ff5563 100644 --- a/common/strmatcher/benchmark_test.go +++ b/common/strmatcher/benchmark_test.go @@ -35,7 +35,7 @@ func BenchmarkFullMatcherGroup(b *testing.B) { } func BenchmarkMarchGroup(b *testing.B) { - g := NewMatcherGroup() + g := new(MatcherGroup) for i := 1; i <= 1024; i++ { m, err := Domain.New(strconv.Itoa(i) + ".v2ray.com") common.Must(err) @@ -49,7 +49,7 @@ func BenchmarkMarchGroup(b *testing.B) { } func BenchmarkCachedMarchGroup(b *testing.B) { - g := NewMatcherGroup() + g := new(MatcherGroup) for i := 1; i <= 1024; i++ { m, err := Domain.New(strconv.Itoa(i) + ".v2ray.com") common.Must(err) diff --git a/common/strmatcher/domain_matcher.go b/common/strmatcher/domain_matcher.go index 1d8cb0674..317913240 100644 --- a/common/strmatcher/domain_matcher.go +++ b/common/strmatcher/domain_matcher.go @@ -11,6 +11,8 @@ type node struct { sub map[string]*node } +// DomainMatcherGroup is a IndexMatcher for a large set of Domain matchers. +// Visible for testing only. type DomainMatcherGroup struct { root *node } diff --git a/common/strmatcher/matchers_test.go b/common/strmatcher/matchers_test.go index d2524c3fc..f952c0b61 100644 --- a/common/strmatcher/matchers_test.go +++ b/common/strmatcher/matchers_test.go @@ -59,6 +59,12 @@ func TestMatcher(t *testing.T) { input: "xv2ray.com", output: false, }, + { + pattern: "v2ray.com", + mType: Regex, + input: "v2rayxcom", + output: true, + }, } for _, test := range cases { matcher, err := test.mType.New(test.pattern) diff --git a/common/strmatcher/strmatcher.go b/common/strmatcher/strmatcher.go index 5aa50b819..17a6ca482 100644 --- a/common/strmatcher/strmatcher.go +++ b/common/strmatcher/strmatcher.go @@ -8,19 +8,27 @@ import ( "v2ray.com/core/common/task" ) +// Matcher is the interface to determine a string matches a pattern. type Matcher interface { + // Match returns true if the given string matches a predefined pattern. Match(string) bool } +// Type is the type of the matcher. type Type byte const ( + // Full is the type of matcher that the input string must exactly equal to the pattern. Full Type = iota + // Substr is the type of matcher that the input string must contain the pattern as a sub-string. Substr + // Domain is the type of matcher that the input string must be a sub-domain or itself of the pattern. Domain + // Regex is the type of matcher that the input string must matches the regular-expression pattern. Regex ) +// New creates a new Matcher based on the given pattern. func (t Type) New(pattern string) (Matcher, error) { switch t { case Full: @@ -42,8 +50,10 @@ func (t Type) New(pattern string) (Matcher, error) { } } +// IndexMatcher is the interface for matching with a group of matchers. type IndexMatcher interface { - Match(pattern string) uint32 + // Match returns the the index of a matcher that matches the input. It returns 0 if no such matcher exists. + Match(input string) uint32 } type matcherEntry struct { @@ -51,6 +61,8 @@ type matcherEntry struct { id uint32 } +// MatcherGroup is an implementation of IndexMatcher. +// Empty initialization works. type MatcherGroup struct { count uint32 fullMatcher FullMatcherGroup @@ -58,10 +70,7 @@ type MatcherGroup struct { otherMatchers []matcherEntry } -func NewMatcherGroup() *MatcherGroup { - return &MatcherGroup{} -} - +// Add adds a new Matcher into the MatcherGroup, and returns its index. The index will never be 0. func (g *MatcherGroup) Add(m Matcher) uint32 { g.count++ c := g.count @@ -81,6 +90,7 @@ func (g *MatcherGroup) Add(m Matcher) uint32 { return c } +// Match implements IndexMatcher.Match. func (g *MatcherGroup) Match(pattern string) uint32 { if c := g.fullMatcher.Match(pattern); c > 0 { return c @@ -99,6 +109,7 @@ func (g *MatcherGroup) Match(pattern string) uint32 { return 0 } +// Size returns the number of matchers in the MatcherGroup. func (g *MatcherGroup) Size() uint32 { return g.count } @@ -108,6 +119,7 @@ type cacheEntry struct { result uint32 } +// CachedMatcherGroup is a IndexMatcher with cachable results. type CachedMatcherGroup struct { sync.RWMutex group *MatcherGroup @@ -115,6 +127,7 @@ type CachedMatcherGroup struct { cleanup *task.Periodic } +// NewCachedMatcherGroup creats a new CachedMatcherGroup. func NewCachedMatcherGroup(g *MatcherGroup) *CachedMatcherGroup { r := &CachedMatcherGroup{ group: g, @@ -139,6 +152,7 @@ func NewCachedMatcherGroup(g *MatcherGroup) *CachedMatcherGroup { return r } +// Match implements IndexMatcher.Match. func (g *CachedMatcherGroup) Match(pattern string) uint32 { g.RLock() r, f := g.cache[pattern]