mirror of
https://github.com/alibaba/higress.git
synced 2026-05-28 22:57:31 +08:00
refactor(mcp-server): improve host matching logic using HostMatcher p… (#2890)
This commit is contained in:
@@ -13,6 +13,9 @@ type RuleType string
|
|||||||
// UpstreamType defines the type of matching rule
|
// UpstreamType defines the type of matching rule
|
||||||
type UpstreamType string
|
type UpstreamType string
|
||||||
|
|
||||||
|
// HostMatchType defines the type of host matching
|
||||||
|
type HostMatchType int
|
||||||
|
|
||||||
const (
|
const (
|
||||||
ExactMatch RuleType = "exact"
|
ExactMatch RuleType = "exact"
|
||||||
PrefixMatch RuleType = "prefix"
|
PrefixMatch RuleType = "prefix"
|
||||||
@@ -23,8 +26,18 @@ const (
|
|||||||
RestUpstream UpstreamType = "rest"
|
RestUpstream UpstreamType = "rest"
|
||||||
SSEUpstream UpstreamType = "sse"
|
SSEUpstream UpstreamType = "sse"
|
||||||
StreamableUpstream UpstreamType = "streamable"
|
StreamableUpstream UpstreamType = "streamable"
|
||||||
|
|
||||||
|
HostExact HostMatchType = iota
|
||||||
|
HostPrefix
|
||||||
|
HostSuffix
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// HostMatcher defines the structure for host matching
|
||||||
|
type HostMatcher struct {
|
||||||
|
matchType HostMatchType
|
||||||
|
host string
|
||||||
|
}
|
||||||
|
|
||||||
// MatchRule defines the structure for a matching rule
|
// MatchRule defines the structure for a matching rule
|
||||||
type MatchRule struct {
|
type MatchRule struct {
|
||||||
MatchRuleDomain string `json:"match_rule_domain"` // Domain pattern, supports wildcards
|
MatchRuleDomain string `json:"match_rule_domain"` // Domain pattern, supports wildcards
|
||||||
@@ -84,11 +97,38 @@ func ParseMatchList(matchListConfig []interface{}) []MatchRule {
|
|||||||
return matchList
|
return matchList
|
||||||
}
|
}
|
||||||
|
|
||||||
// convertWildcardToRegex converts wildcard pattern to regex pattern
|
// stripPortFromHost removes port from host string
|
||||||
func convertWildcardToRegex(pattern string) string {
|
// Port removing code is inspired by
|
||||||
pattern = regexp.QuoteMeta(pattern)
|
// https://github.com/envoyproxy/envoy/blob/v1.17.0/source/common/http/header_utility.cc#L219
|
||||||
pattern = "^" + strings.ReplaceAll(pattern, "\\*", ".*") + "$"
|
func stripPortFromHost(reqHost string) string {
|
||||||
return pattern
|
portStart := strings.LastIndexByte(reqHost, ':')
|
||||||
|
if portStart != -1 {
|
||||||
|
// According to RFC3986 v6 address is always enclosed in "[]".
|
||||||
|
// section 3.2.2.
|
||||||
|
v6EndIndex := strings.LastIndexByte(reqHost, ']')
|
||||||
|
if v6EndIndex == -1 || v6EndIndex < portStart {
|
||||||
|
if portStart+1 <= len(reqHost) {
|
||||||
|
return reqHost[:portStart]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return reqHost
|
||||||
|
}
|
||||||
|
|
||||||
|
// parseHostPattern parses a host pattern and returns a HostMatcher
|
||||||
|
func parseHostPattern(pattern string) HostMatcher {
|
||||||
|
var hostMatcher HostMatcher
|
||||||
|
if strings.HasPrefix(pattern, "*") {
|
||||||
|
hostMatcher.matchType = HostSuffix
|
||||||
|
hostMatcher.host = pattern[1:]
|
||||||
|
} else if strings.HasSuffix(pattern, "*") {
|
||||||
|
hostMatcher.matchType = HostPrefix
|
||||||
|
hostMatcher.host = pattern[:len(pattern)-1]
|
||||||
|
} else {
|
||||||
|
hostMatcher.matchType = HostExact
|
||||||
|
hostMatcher.host = pattern
|
||||||
|
}
|
||||||
|
return hostMatcher
|
||||||
}
|
}
|
||||||
|
|
||||||
// matchPattern checks if the target matches the pattern based on rule type
|
// matchPattern checks if the target matches the pattern based on rule type
|
||||||
@@ -117,15 +157,29 @@ func matchPattern(pattern string, target string, ruleType RuleType) bool {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// matchDomain checks if the domain matches the pattern
|
// matchDomain checks if the domain matches the pattern using HostMatcher approach
|
||||||
func matchDomain(domain string, pattern string) bool {
|
func matchDomain(domain string, pattern string) bool {
|
||||||
if pattern == "" || pattern == "*" {
|
if pattern == "" || pattern == "*" {
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
// Convert wildcard pattern to regex pattern
|
|
||||||
regexPattern := convertWildcardToRegex(pattern)
|
// Strip port from domain
|
||||||
matched, _ := regexp.MatchString(regexPattern, domain)
|
domain = stripPortFromHost(domain)
|
||||||
return matched
|
|
||||||
|
// Parse the pattern into a HostMatcher
|
||||||
|
hostMatcher := parseHostPattern(pattern)
|
||||||
|
|
||||||
|
// Perform matching based on match type
|
||||||
|
switch hostMatcher.matchType {
|
||||||
|
case HostSuffix:
|
||||||
|
return strings.HasSuffix(domain, hostMatcher.host)
|
||||||
|
case HostPrefix:
|
||||||
|
return strings.HasPrefix(domain, hostMatcher.host)
|
||||||
|
case HostExact:
|
||||||
|
return domain == hostMatcher.host
|
||||||
|
default:
|
||||||
|
return false
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// matchDomainAndPath checks if both domain and path match the rule
|
// matchDomainAndPath checks if both domain and path match the rule
|
||||||
|
|||||||
Reference in New Issue
Block a user