Skip to content

Commit 03b4ed4

Browse files
committed
Refactor matching and hostname specificity
1 parent 170192d commit 03b4ed4

File tree

5 files changed

+89
-33
lines changed

5 files changed

+89
-33
lines changed

internal/state/dataplane/configuration.go

Lines changed: 1 addition & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,6 @@ import (
44
"context"
55
"fmt"
66
"sort"
7-
"strings"
87

98
"k8s.io/apimachinery/pkg/types"
109
"sigs.k8s.io/gateway-api/apis/v1beta1"
@@ -569,8 +568,6 @@ func convertPathType(pathType v1beta1.PathMatchType) PathType {
569568
}
570569

571570
// listenerHostnameMoreSpecific returns true if host1 is more specific than host2.
572-
//
573-
// This function assumes that host1 and host2 match, either exactly or as a substring.
574571
func listenerHostnameMoreSpecific(host1, host2 *v1beta1.Hostname) bool {
575572
var host1Str, host2Str string
576573
if host1 != nil {
@@ -581,15 +578,5 @@ func listenerHostnameMoreSpecific(host1, host2 *v1beta1.Hostname) bool {
581578
host2Str = string(*host2)
582579
}
583580

584-
host1Segments := len(strings.Split(host1Str, "."))
585-
host2Segments := len(strings.Split(host2Str, "."))
586-
if host1Segments > host2Segments {
587-
return true
588-
}
589-
590-
if host2Segments > host1Segments {
591-
return false
592-
}
593-
594-
return len(host1Str) >= len(host2Str)
581+
return graph.GetMoreSpecificHostname(host1Str, host2Str) == host1Str
595582
}

internal/state/dataplane/configuration_test.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1996,8 +1996,6 @@ func TestConvertPathType(t *testing.T) {
19961996
}
19971997

19981998
func TestHostnameMoreSpecific(t *testing.T) {
1999-
g := NewGomegaWithT(t)
2000-
20011999
tests := []struct {
20022000
host1 *v1beta1.Hostname
20032001
host2 *v1beta1.Hostname
@@ -2050,6 +2048,8 @@ func TestHostnameMoreSpecific(t *testing.T) {
20502048

20512049
for _, tc := range tests {
20522050
t.Run(tc.msg, func(t *testing.T) {
2051+
g := NewGomegaWithT(t)
2052+
20532053
g.Expect(listenerHostnameMoreSpecific(tc.host1, tc.host2)).To(Equal(tc.host1Wins))
20542054
})
20552055
}

internal/state/graph/httproute.go

Lines changed: 75 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -402,33 +402,91 @@ func findAcceptedHostnames(listenerHostname *v1beta1.Hostname, routeHostnames []
402402
return []string{hostname}
403403
}
404404

405-
match := func(h v1beta1.Hostname) bool {
406-
if hostname == "" {
407-
return true
408-
}
405+
var result []string
409406

407+
for _, h := range routeHostnames {
410408
routeHost := string(h)
411-
return routeHost == hostname || wildcardMatch(hostname, routeHost) || wildcardMatch(routeHost, hostname)
409+
if match(hostname, routeHost) {
410+
result = append(result, GetMoreSpecificHostname(hostname, routeHost))
411+
}
412412
}
413413

414-
var result []string
414+
return result
415+
}
415416

416-
for _, h := range routeHostnames {
417-
if match(h) {
418-
if len(hostname) > len(h) {
419-
result = append(result, hostname)
420-
} else {
421-
result = append(result, string(h))
417+
func match(listenerHost, routeHost string) bool {
418+
if listenerHost == "" {
419+
return true
420+
}
421+
422+
if routeHost == listenerHost {
423+
return true
424+
}
425+
426+
wildcardMatch := func(host1, host2 string) bool {
427+
return strings.HasPrefix(host1, "*.") && strings.HasSuffix(host2, strings.TrimPrefix(host1, "*"))
428+
}
429+
430+
// check if listenerHost is a wildcard and routeHost matches
431+
if wildcardMatch(listenerHost, routeHost) {
432+
return true
433+
}
434+
435+
// check if routeHost is a wildcard and listener matchess
436+
return wildcardMatch(routeHost, listenerHost)
437+
}
438+
439+
// GetMoreSpecificHostname returns the more specific hostname between the two inputs.
440+
//
441+
// This function assumes that the two hostnames match each other, either:
442+
// - Exactly
443+
// - One as a substring of the other
444+
// - Both as substrings of some parent wildcard
445+
func GetMoreSpecificHostname(hostname1, hostname2 string) string {
446+
if hostname1 == hostname2 {
447+
return hostname1
448+
}
449+
450+
if hostname1 == "" {
451+
return hostname2
452+
} else if hostname2 == "" {
453+
return hostname1
454+
}
455+
456+
// Compare if wildcards are present
457+
if strings.HasPrefix(hostname1, "*.") {
458+
if strings.HasPrefix(hostname2, "*.") {
459+
subdomains1 := strings.Split(hostname1, ".")
460+
subdomains2 := strings.Split(hostname2, ".")
461+
462+
// Compare number of subdomains
463+
if len(subdomains1) > len(subdomains2) {
464+
return hostname1
422465
}
466+
467+
return hostname2
423468
}
469+
470+
return hostname2
471+
} else if strings.HasPrefix(hostname2, "*.") {
472+
return hostname1
424473
}
425474

426-
return result
427-
}
475+
subdomains1 := strings.Split(hostname1, ".")
476+
subdomains2 := strings.Split(hostname2, ".")
477+
478+
// Compare number of subdomains
479+
if len(subdomains1) > len(subdomains2) {
480+
return hostname1
481+
} else if len(subdomains1) < len(subdomains2) {
482+
return hostname2
483+
}
484+
485+
if len(hostname1) > len(hostname2) {
486+
return hostname1
487+
}
428488

429-
// wildcardMatch checks if host1 is a wildcard host, and if so, checks if host2 is a match for that wildcard.
430-
func wildcardMatch(host1, host2 string) bool {
431-
return strings.HasPrefix(host1, "*.") && strings.HasSuffix(host2, strings.TrimPrefix(host1, "*"))
489+
return hostname2
432490
}
433491

434492
func routeAllowedByListener(

internal/state/graph/httproute_test.go

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1280,6 +1280,12 @@ func TestFindAcceptedHostnames(t *testing.T) {
12801280
expected: []string{"*.example.com"},
12811281
msg: "route wildcard hostname; nil listener hostname",
12821282
},
1283+
{
1284+
listenerHostname: &listenerHostnameWildcard,
1285+
routeHostnames: []v1beta1.Hostname{"*.bar.example.com"},
1286+
expected: []string{"*.bar.example.com"},
1287+
msg: "route and listener wildcard hostnames",
1288+
},
12831289
}
12841290

12851291
for _, test := range tests {

internal/state/graph/validation_test.go

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,11 @@ func TestValidateHostname(t *testing.T) {
3232
expectErr: true,
3333
name: "invalid hostname",
3434
},
35+
{
36+
hostname: "*.example.*.com",
37+
expectErr: true,
38+
name: "invalid wildcard hostname",
39+
},
3540
}
3641

3742
for _, test := range tests {

0 commit comments

Comments
 (0)