mirror of
https://github.com/alibaba/higress.git
synced 2026-06-09 20:57:32 +08:00
feat: add more precedence rules for route matching (#214)
Signed-off-by: charlie <qianglin98@qq.com>
This commit is contained in:
@@ -38,6 +38,11 @@ type WrapperConfig struct {
|
||||
AnnotationsConfig *annotations.Ingress
|
||||
}
|
||||
|
||||
type WrapperConfigWithRuleKey struct {
|
||||
Config *config.Config
|
||||
RuleKey string
|
||||
}
|
||||
|
||||
type WrapperGateway struct {
|
||||
Gateway *networking.Gateway
|
||||
WrapperConfig *WrapperConfig
|
||||
@@ -70,6 +75,8 @@ type WrapperHTTPRoute struct {
|
||||
OriginPathType PathType
|
||||
WeightTotal int32
|
||||
IsDefaultBackend bool
|
||||
RuleKey string
|
||||
RuleHash uint32
|
||||
}
|
||||
|
||||
func (w *WrapperHTTPRoute) Meta() string {
|
||||
|
||||
@@ -149,7 +149,8 @@ type ConvertOptions struct {
|
||||
|
||||
IngressDomainCache *IngressDomainCache
|
||||
|
||||
HostAndPath2Ingress map[string]*config.Config
|
||||
// the host, path, headers, params of rule => ingress
|
||||
Route2Ingress map[uint32]*WrapperConfigWithRuleKey
|
||||
|
||||
// Record valid/invalid routes from ingress
|
||||
IngressRouteCache *IngressRouteCache
|
||||
|
||||
@@ -175,6 +175,9 @@ func SortHTTPRoutes(routes []*WrapperHTTPRoute) {
|
||||
return false
|
||||
}
|
||||
|
||||
// default backend,user specified root path => path type => path length =>
|
||||
// methods => header => query param
|
||||
// refer https://gateway-api.sigs.k8s.io/v1alpha2/references/spec/#gateway.networking.k8s.io/v1beta1.HTTPRouteSpec
|
||||
sort.SliceStable(routes, func(i, j int) bool {
|
||||
// Move default backend to end
|
||||
if isDefaultBackend(routes[i]) {
|
||||
@@ -193,7 +196,27 @@ func SortHTTPRoutes(routes []*WrapperHTTPRoute) {
|
||||
}
|
||||
|
||||
if routes[i].OriginPathType == routes[j].OriginPathType {
|
||||
return len(routes[i].OriginPath) > len(routes[j].OriginPath)
|
||||
if in, jn := len(routes[i].OriginPath), len(routes[j].OriginPath); in != jn {
|
||||
return in > jn
|
||||
}
|
||||
|
||||
match1, match2 := routes[i].HTTPRoute.Match[0], routes[j].HTTPRoute.Match[0]
|
||||
// methods
|
||||
if in, jn := len(match1.Method.GetRegex()), len(match2.Method.GetRegex()); in != jn {
|
||||
if in != 0 && jn != 0 {
|
||||
return in < jn
|
||||
}
|
||||
return in != 0
|
||||
}
|
||||
// headers
|
||||
if in, jn := len(match1.Headers), len(match2.Headers); in != jn {
|
||||
return in > jn
|
||||
}
|
||||
// query params
|
||||
if in, jn := len(match1.QueryParams), len(match2.QueryParams); in != jn {
|
||||
return in > jn
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
if routes[i].OriginPathType == Exact {
|
||||
|
||||
@@ -416,3 +416,143 @@ func TestSortRoutes(t *testing.T) {
|
||||
t.Fatal("should be test-3")
|
||||
}
|
||||
}
|
||||
|
||||
// TestSortHTTPRoutesWithMoreRules include headers, query params, methods
|
||||
func TestSortHTTPRoutesWithMoreRules(t *testing.T) {
|
||||
input := []struct {
|
||||
order string
|
||||
pathType PathType
|
||||
path string
|
||||
method *networking.StringMatch
|
||||
header map[string]*networking.StringMatch
|
||||
queryParam map[string]*networking.StringMatch
|
||||
}{
|
||||
{
|
||||
order: "1",
|
||||
pathType: Exact,
|
||||
path: "/bar",
|
||||
},
|
||||
{
|
||||
order: "2",
|
||||
pathType: Prefix,
|
||||
path: "/bar",
|
||||
},
|
||||
{
|
||||
order: "3",
|
||||
pathType: Prefix,
|
||||
path: "/bar",
|
||||
method: &networking.StringMatch{
|
||||
MatchType: &networking.StringMatch_Regex{Regex: "GET|PUT"},
|
||||
},
|
||||
},
|
||||
{
|
||||
order: "4",
|
||||
pathType: Prefix,
|
||||
path: "/bar",
|
||||
method: &networking.StringMatch{
|
||||
MatchType: &networking.StringMatch_Regex{Regex: "GET"},
|
||||
},
|
||||
},
|
||||
{
|
||||
order: "5",
|
||||
pathType: Prefix,
|
||||
path: "/bar",
|
||||
header: map[string]*networking.StringMatch{
|
||||
"foo": {
|
||||
MatchType: &networking.StringMatch_Exact{Exact: "bar"},
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
order: "6",
|
||||
pathType: Prefix,
|
||||
path: "/bar",
|
||||
header: map[string]*networking.StringMatch{
|
||||
"foo": {
|
||||
MatchType: &networking.StringMatch_Exact{Exact: "bar"},
|
||||
},
|
||||
"bar": {
|
||||
MatchType: &networking.StringMatch_Exact{Exact: "foo"},
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
order: "7",
|
||||
pathType: Prefix,
|
||||
path: "/bar",
|
||||
queryParam: map[string]*networking.StringMatch{
|
||||
"foo": {
|
||||
MatchType: &networking.StringMatch_Exact{Exact: "bar"},
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
order: "8",
|
||||
pathType: Prefix,
|
||||
path: "/bar",
|
||||
queryParam: map[string]*networking.StringMatch{
|
||||
"foo": {
|
||||
MatchType: &networking.StringMatch_Exact{Exact: "bar"},
|
||||
},
|
||||
"bar": {
|
||||
MatchType: &networking.StringMatch_Exact{Exact: "foo"},
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
order: "9",
|
||||
pathType: Prefix,
|
||||
path: "/bar",
|
||||
method: &networking.StringMatch{
|
||||
MatchType: &networking.StringMatch_Regex{Regex: "GET"},
|
||||
},
|
||||
queryParam: map[string]*networking.StringMatch{
|
||||
"foo": {
|
||||
MatchType: &networking.StringMatch_Exact{Exact: "bar"},
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
order: "10",
|
||||
pathType: Prefix,
|
||||
path: "/bar",
|
||||
method: &networking.StringMatch{
|
||||
MatchType: &networking.StringMatch_Regex{Regex: "GET"},
|
||||
},
|
||||
queryParam: map[string]*networking.StringMatch{
|
||||
"bar": {
|
||||
MatchType: &networking.StringMatch_Exact{Exact: "foo"},
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
origin := []string{"1", "2", "3", "4", "5", "6", "7", "8", "9", "10"}
|
||||
expect := []string{"1", "9", "10", "4", "3", "6", "5", "8", "7", "2"}
|
||||
|
||||
var list []*WrapperHTTPRoute
|
||||
for idx, val := range input {
|
||||
list = append(list, &WrapperHTTPRoute{
|
||||
OriginPath: val.path,
|
||||
OriginPathType: val.pathType,
|
||||
HTTPRoute: &networking.HTTPRoute{
|
||||
Name: origin[idx],
|
||||
Match: []*networking.HTTPMatchRequest{
|
||||
{
|
||||
Method: val.method,
|
||||
Headers: val.header,
|
||||
QueryParams: val.queryParam,
|
||||
},
|
||||
},
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
SortHTTPRoutes(list)
|
||||
|
||||
for idx, val := range list {
|
||||
if val.HTTPRoute.Name != expect[idx] {
|
||||
t.Fatalf("should be %s, but got %s", expect[idx], val.HTTPRoute.Name)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user