domain_matcher.go 1.6 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788
  1. package strmatcher
  2. import "strings"
  3. func breakDomain(domain string) []string {
  4. return strings.Split(domain, ".")
  5. }
  6. type node struct {
  7. values []uint32
  8. sub map[string]*node
  9. }
  10. // DomainMatcherGroup is a IndexMatcher for a large set of Domain matchers.
  11. // Visible for testing only.
  12. type DomainMatcherGroup struct {
  13. root *node
  14. }
  15. func (g *DomainMatcherGroup) Add(domain string, value uint32) {
  16. if g.root == nil {
  17. g.root = new(node)
  18. }
  19. current := g.root
  20. parts := breakDomain(domain)
  21. for i := len(parts) - 1; i >= 0; i-- {
  22. if len(current.values) > 0 {
  23. // if current node is already a match, it is not necessary to match further.
  24. return
  25. }
  26. part := parts[i]
  27. if current.sub == nil {
  28. current.sub = make(map[string]*node)
  29. }
  30. next := current.sub[part]
  31. if next == nil {
  32. next = new(node)
  33. current.sub[part] = next
  34. }
  35. current = next
  36. }
  37. current.values = append(current.values, value)
  38. current.sub = nil // shortcut sub nodes as current node is a match.
  39. }
  40. func (g *DomainMatcherGroup) addMatcher(m domainMatcher, value uint32) {
  41. g.Add(string(m), value)
  42. }
  43. func (g *DomainMatcherGroup) Match(domain string) []uint32 {
  44. if domain == "" {
  45. return nil
  46. }
  47. current := g.root
  48. if current == nil {
  49. return nil
  50. }
  51. nextPart := func(idx int) int {
  52. for i := idx - 1; i >= 0; i-- {
  53. if domain[i] == '.' {
  54. return i
  55. }
  56. }
  57. return -1
  58. }
  59. idx := len(domain)
  60. for {
  61. if idx == -1 || current.sub == nil {
  62. break
  63. }
  64. nidx := nextPart(idx)
  65. part := domain[nidx+1 : idx]
  66. next := current.sub[part]
  67. if next == nil {
  68. break
  69. }
  70. current = next
  71. idx = nidx
  72. }
  73. return current.values
  74. }