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 }