Skip to content

Commit ba66c20

Browse files
authored
extproc: fixes router to make the first match win (#510)
**Commit Message** Previously, there was a bug in router's code where the matching rule search doesn't break and it iterated over all rules even when there's a matching rule found in the middle. That was a bug in the sense that it is not only an inefficient but also semantically wrong since the last match wins as opposed to the specification of GW API [1] which specifies "If ties still exist within an HTTPRoute, matching precedence MUST be granted to the FIRST matching rule (in list order) with a match meeting the above criteria.". 1: https://gateway-api.sigs.k8s.io/reference/spec/#gateway.networking.k8s.io%2fv1.HTTPRouteRule --------- Signed-off-by: Takeshi Yoneda <[email protected]>
1 parent 044f85f commit ba66c20

File tree

2 files changed

+18
-2
lines changed

2 files changed

+18
-2
lines changed

internal/extproc/router/router.go

+4-2
Original file line numberDiff line numberDiff line change
@@ -32,14 +32,16 @@ func New(config *filterapi.Config, newCustomFn x.NewCustomRouterFn) (x.Router, e
3232
// Calculate implements [x.Router.Calculate].
3333
func (r *router) Calculate(headers map[string]string) (backend *filterapi.Backend, err error) {
3434
var rule *filterapi.RouteRule
35+
outer:
3536
for i := range r.rules {
3637
_rule := &r.rules[i]
37-
for _, hdr := range _rule.Headers {
38+
for j := range _rule.Headers {
39+
hdr := &_rule.Headers[j]
3840
v, ok := headers[string(hdr.Name)]
3941
// Currently, we only do the exact matching.
4042
if ok && v == hdr.Value {
4143
rule = _rule
42-
break
44+
break outer
4345
}
4446
}
4547
}

internal/extproc/router/router_test.go

+14
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,14 @@ func TestRouter_Calculate(t *testing.T) {
4444
outSchema := filterapi.VersionedAPISchema{Name: filterapi.APISchemaOpenAI}
4545
_r, err := New(&filterapi.Config{
4646
Rules: []filterapi.RouteRule{
47+
{
48+
Backends: []filterapi.Backend{
49+
{Name: "cat", Schema: outSchema},
50+
},
51+
Headers: []filterapi.HeaderMatch{
52+
{Name: "x-some-random-non-model-header", Value: "dog"},
53+
},
54+
},
4755
{
4856
Backends: []filterapi.Backend{
4957
{Name: "foo", Schema: outSchema, Weight: 1},
@@ -113,6 +121,12 @@ func TestRouter_Calculate(t *testing.T) {
113121
require.Greater(t, chosenNames["foo"], 200)
114122
})
115123

124+
t.Run("first match win", func(t *testing.T) {
125+
b, err := r.Calculate(map[string]string{"x-some-random-non-model-header": "dog", "x-model-name": "llama3.3333"})
126+
require.NoError(t, err)
127+
require.Equal(t, "cat", b.Name)
128+
})
129+
116130
t.Run("concurrent access", func(t *testing.T) {
117131
var wg sync.WaitGroup
118132
wg.Add(1000)

0 commit comments

Comments
 (0)