diff --git a/plugins/wasm-go/pkg/matcher/rule_matcher.go b/plugins/wasm-go/pkg/matcher/rule_matcher.go index 317044634..52e15a9a2 100644 --- a/plugins/wasm-go/pkg/matcher/rule_matcher.go +++ b/plugins/wasm-go/pkg/matcher/rule_matcher.go @@ -30,6 +30,7 @@ const ( Route Category = iota Host Service + RoutePrefix ) type MatchType int @@ -41,10 +42,11 @@ const ( ) const ( - RULES_KEY = "_rules_" - MATCH_ROUTE_KEY = "_match_route_" - MATCH_DOMAIN_KEY = "_match_domain_" - MATCH_SERVICE_KEY = "_match_service_" + RULES_KEY = "_rules_" + MATCH_ROUTE_KEY = "_match_route_" + MATCH_DOMAIN_KEY = "_match_domain_" + MATCH_SERVICE_KEY = "_match_service_" + MATCH_ROUTE_PREFIX_KEY = "_match_route_prefix_" ) type HostMatcher struct { @@ -53,11 +55,12 @@ type HostMatcher struct { } type RuleConfig[PluginConfig any] struct { - category Category - routes map[string]struct{} - services map[string]struct{} - hosts []HostMatcher - config PluginConfig + category Category + routes map[string]struct{} + services map[string]struct{} + routePrefixs map[string]struct{} + hosts []HostMatcher + config PluginConfig } type RuleMatcher[PluginConfig any] struct { @@ -92,6 +95,14 @@ func (m RuleMatcher[PluginConfig]) GetMatchConfig() (*PluginConfig, error) { return &rule.config, nil } } + // category == RoutePrefix + if rule.category == RoutePrefix { + for routePrefix := range rule.routePrefixs { + if strings.HasPrefix(string(routeName), routePrefix) { + return &rule.config, nil + } + } + } // category == Cluster if m.serviceMatch(rule, string(serviceName)) { return &rule.config, nil @@ -152,18 +163,22 @@ func (m *RuleMatcher[PluginConfig]) ParseRuleConfig(config gjson.Result, rule.routes = m.parseRouteMatchConfig(ruleJson) rule.hosts = m.parseHostMatchConfig(ruleJson) rule.services = m.parseServiceMatchConfig(ruleJson) + rule.routePrefixs = m.parseRoutePrefixMatchConfig(ruleJson) noRoute := len(rule.routes) == 0 noHosts := len(rule.hosts) == 0 noService := len(rule.services) == 0 - if boolToInt(noRoute)+boolToInt(noService)+boolToInt(noHosts) != 2 { - return errors.New("there is only one of '_match_route_', '_match_domain_' and '_match_service_' can present in configuration.") + noRoutePrefix := len(rule.routePrefixs) == 0 + if boolToInt(noRoute)+boolToInt(noService)+boolToInt(noHosts)+boolToInt(noRoutePrefix) != 3 { + return errors.New("there is only one of '_match_route_', '_match_domain_', '_match_service_' and '_match_route_prefix_' can present in configuration.") } if !noRoute { rule.category = Route } else if !noHosts { rule.category = Host - } else { + } else if !noService { rule.category = Service + } else { + rule.category = RoutePrefix } m.ruleConfig = append(m.ruleConfig, rule) } @@ -182,6 +197,18 @@ func (m RuleMatcher[PluginConfig]) parseRouteMatchConfig(config gjson.Result) ma return routes } +func (m RuleMatcher[PluginConfig]) parseRoutePrefixMatchConfig(config gjson.Result) map[string]struct{} { + keys := config.Get(MATCH_ROUTE_PREFIX_KEY).Array() + routePrefixs := make(map[string]struct{}) + for _, item := range keys { + routePrefix := item.String() + if routePrefix != "" { + routePrefixs[routePrefix] = struct{}{} + } + } + return routePrefixs +} + func (m RuleMatcher[PluginConfig]) parseServiceMatchConfig(config gjson.Result) map[string]struct{} { keys := config.Get(MATCH_SERVICE_KEY).Array() clusters := make(map[string]struct{}) diff --git a/plugins/wasm-go/pkg/matcher/rule_matcher_test.go b/plugins/wasm-go/pkg/matcher/rule_matcher_test.go index 7b4b84605..460f414aa 100644 --- a/plugins/wasm-go/pkg/matcher/rule_matcher_test.go +++ b/plugins/wasm-go/pkg/matcher/rule_matcher_test.go @@ -229,7 +229,7 @@ func TestParseRuleConfig(t *testing.T) { }, { name: "rules config", - config: `{"_rules_":[{"_match_domain_":["*.example.com","www.*","*","www.abc.com"],"name":"john", "age":18},{"_match_route_":["test1","test2"],"name":"ann", "age":16},{"_match_service_":["test1.dns","test2.static:8080"],"name":"ann", "age":16}]}`, + config: `{"_rules_":[{"_match_domain_":["*.example.com","www.*","*","www.abc.com"],"name":"john", "age":18},{"_match_route_":["test1","test2"],"name":"ann", "age":16},{"_match_service_":["test1.dns","test2.static:8080"],"name":"ann", "age":16},{"_match_route_prefix_":["api1","api2"],"name":"ann", "age":16}]}`, expected: RuleMatcher[customConfig]{ ruleConfig: []RuleConfig[customConfig]{ { @@ -252,8 +252,9 @@ func TestParseRuleConfig(t *testing.T) { host: "www.abc.com", }, }, - routes: map[string]struct{}{}, - services: map[string]struct{}{}, + routes: map[string]struct{}{}, + services: map[string]struct{}{}, + routePrefixs: map[string]struct{}{}, config: customConfig{ name: "john", age: 18, @@ -265,7 +266,8 @@ func TestParseRuleConfig(t *testing.T) { "test1": {}, "test2": {}, }, - services: map[string]struct{}{}, + services: map[string]struct{}{}, + routePrefixs: map[string]struct{}{}, config: customConfig{ name: "ann", age: 16, @@ -273,11 +275,25 @@ func TestParseRuleConfig(t *testing.T) { }, { category: Service, + routes: map[string]struct{}{}, services: map[string]struct{}{ "test1.dns": {}, "test2.static:8080": {}, }, - routes: map[string]struct{}{}, + routePrefixs: map[string]struct{}{}, + config: customConfig{ + name: "ann", + age: 16, + }, + }, + { + category: RoutePrefix, + routes: map[string]struct{}{}, + services: map[string]struct{}{}, + routePrefixs: map[string]struct{}{ + "api1": {}, + "api2": {}, + }, config: customConfig{ name: "ann", age: 16, @@ -294,17 +310,17 @@ func TestParseRuleConfig(t *testing.T) { { name: "invalid rule", config: `{"_rules_":[{"_match_domain_":["*"],"_match_route_":["test"]}]}`, - errMsg: "there is only one of '_match_route_', '_match_domain_' and '_match_service_' can present in configuration.", + errMsg: "there is only one of '_match_route_', '_match_domain_', '_match_service_' and '_match_route_prefix_' can present in configuration.", }, { name: "invalid rule", config: `{"_rules_":[{"_match_domain_":["*"],"_match_service_":["test.dns"]}]}`, - errMsg: "there is only one of '_match_route_', '_match_domain_' and '_match_service_' can present in configuration.", + errMsg: "there is only one of '_match_route_', '_match_domain_', '_match_service_' and '_match_route_prefix_' can present in configuration.", }, { name: "invalid rule", config: `{"_rules_":[{"age":16}]}`, - errMsg: "there is only one of '_match_route_', '_match_domain_' and '_match_service_' can present in configuration.", + errMsg: "there is only one of '_match_route_', '_match_domain_', '_match_service_' and '_match_route_prefix_' can present in configuration.", }, } for _, c := range cases { @@ -378,7 +394,8 @@ func TestParseOverrideConfig(t *testing.T) { "r1": {}, "r2": {}, }, - services: map[string]struct{}{}, + services: map[string]struct{}{}, + routePrefixs: map[string]struct{}{}, config: completeConfig{ consumers: []string{"c1", "c2", "c3"}, allow: []string{"c1", "c3"},