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 &regexMatcher{
    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  }