github.com/cnotch/ipchub@v1.1.0/provider/auth/path_matcher.go (about)

     1  // Copyright (c) 2019,CAOHONGJU All rights reserved.
     2  // Use of this source code is governed by a MIT-style
     3  // license that can be found in the LICENSE file.
     4  
     5  package auth
     6  
     7  import (
     8  	"strings"
     9  	"unicode"
    10  
    11  	"github.com/cnotch/ipchub/utils/scan"
    12  )
    13  
    14  const (
    15  	sectionWildcard = "+" // 单段通配符
    16  	endWildcard     = "*" // 0-n段通配符,必须位于结尾
    17  )
    18  
    19  // 行分割
    20  var pathScanner = scan.NewScanner('/', unicode.IsSpace)
    21  
    22  // PathMatcher 路径匹配接口
    23  type PathMatcher interface {
    24  	Match(path string) bool
    25  }
    26  
    27  // NewPathMatcher 创建匹配器
    28  func NewPathMatcher(pathMask string) PathMatcher {
    29  	if strings.TrimSpace(pathMask) == endWildcard {
    30  		return alwaysMatcher{}
    31  	}
    32  
    33  	parts := strings.Split(strings.ToLower(strings.Trim(pathMask, "/")), "/")
    34  	wildcard := parts[len(parts)-1] == endWildcard
    35  	if wildcard {
    36  		parts = parts[0 : len(parts)-1]
    37  	}
    38  	return &pathMacher{parts: parts, wildcardEnd: wildcard}
    39  }
    40  
    41  type alwaysMatcher struct {
    42  }
    43  
    44  func (m alwaysMatcher) Match(path string) bool {
    45  	return true
    46  }
    47  
    48  type pathMacher struct {
    49  	parts       []string
    50  	wildcardEnd bool
    51  }
    52  
    53  func (m *pathMacher) Match(path string) bool {
    54  	path = strings.ToLower(strings.Trim(path, "/"))
    55  	count := partCount(path) + 1
    56  
    57  	if count < len(m.parts) {
    58  		return false
    59  	}
    60  
    61  	if count > len(m.parts) && !m.wildcardEnd {
    62  		return false
    63  	}
    64  
    65  	ok := true
    66  	advance := path
    67  	token := ""
    68  	for i := 0; i < len(m.parts) && ok; i++ {
    69  		advance, token, ok = pathScanner.Scan(advance)
    70  		if sectionWildcard == m.parts[i] {
    71  			continue // 跳过
    72  		}
    73  		if token != m.parts[i] {
    74  			return false
    75  		}
    76  	}
    77  
    78  	return true
    79  }
    80  
    81  func partCount(s string) int {
    82  	n := 0
    83  	for {
    84  		i := strings.IndexByte(s, '/')
    85  		if i == -1 {
    86  			return n
    87  		}
    88  		n++
    89  		s = s[i+1:]
    90  	}
    91  }