Skip to content

Commit 7f9c769

Browse files
committed
fix: HTTPRouteHostnameIntersection test case
Signed-off-by: ashing <[email protected]>
1 parent 80d84b9 commit 7f9c769

File tree

2 files changed

+114
-1
lines changed

2 files changed

+114
-1
lines changed

internal/controller/httproute_controller.go

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -170,6 +170,12 @@ func (r *HTTPRouteReconciler) Reconcile(ctx context.Context, req ctrl.Request) (
170170
}
171171
}
172172

173+
filteredHTTPRoute, err := filterHostnames(gateways, hr.DeepCopy())
174+
if err != nil {
175+
acceptStatus.status = false
176+
acceptStatus.msg = err.Error()
177+
}
178+
173179
var httpRouteErr error
174180
if err := r.processHTTPRoute(tctx, hr); err != nil {
175181
httpRouteErr = err
@@ -201,7 +207,13 @@ func (r *HTTPRouteReconciler) Reconcile(ctx context.Context, req ctrl.Request) (
201207
}
202208
ProcessBackendTrafficPolicy(r.Client, r.Log, tctx)
203209

204-
if err := r.Provider.Update(ctx, tctx, hr); err != nil {
210+
routeToUpdate := hr
211+
if err == nil && filteredHTTPRoute != nil {
212+
r.Log.Info("filteredHTTPRoute", "filteredHTTPRoute", filteredHTTPRoute)
213+
routeToUpdate = filteredHTTPRoute
214+
}
215+
216+
if err := r.Provider.Update(ctx, tctx, routeToUpdate); err != nil {
205217
acceptStatus.status = false
206218
acceptStatus.msg = err.Error()
207219
}

internal/controller/utils.go

Lines changed: 101 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -892,3 +892,104 @@ func IsInvalidKindError(err error) bool {
892892
_, ok := err.(*InvalidKindError)
893893
return ok
894894
}
895+
896+
// filterHostnames accepts a list of gateways and an HTTPRoute, and returns a copy of the HTTPRoute with only the hostnames that match the listener hostnames of the gateways.
897+
// If the HTTPRoute hostnames do not intersect with the listener hostnames of the gateways, it returns an ErrNoMatchingListenerHostname error.
898+
func filterHostnames(gateways []RouteParentRefContext, httpRoute *gatewayv1.HTTPRoute) (*gatewayv1.HTTPRoute, error) {
899+
filteredHostnames := make([]gatewayv1.Hostname, 0)
900+
901+
// If the HTTPRoute does not specify hostnames, we use the union of the listener hostnames of all supported gateways
902+
// If any supported listener does not specify a hostname, the HTTPRoute hostnames remain empty to match any hostname
903+
if len(httpRoute.Spec.Hostnames) == 0 {
904+
hostnames, matchAnyHost := getUnionOfGatewayHostnames(gateways)
905+
if matchAnyHost {
906+
return httpRoute, nil
907+
}
908+
filteredHostnames = hostnames
909+
} else {
910+
// If the HTTPRoute specifies hostnames, we need to find the intersection with the gateway listener hostnames
911+
for _, hostname := range httpRoute.Spec.Hostnames {
912+
if hostnameMatching := getMinimumHostnameIntersection(gateways, hostname); hostnameMatching != "" {
913+
filteredHostnames = append(filteredHostnames, hostnameMatching)
914+
}
915+
}
916+
if len(filteredHostnames) == 0 {
917+
return httpRoute, fmt.Errorf("no matching hostnames in listener")
918+
}
919+
}
920+
921+
log.Debugw("filtered hostnames", zap.Any("httpRouteHostnames", httpRoute.Spec.Hostnames), zap.Any("hostnames", filteredHostnames))
922+
httpRoute.Spec.Hostnames = filteredHostnames
923+
return httpRoute, nil
924+
}
925+
926+
// getUnionOfGatewayHostnames returns the union of the hostnames specified in all supported gateways
927+
// The second return value indicates whether any listener can match any hostname
928+
func getUnionOfGatewayHostnames(gateways []RouteParentRefContext) ([]gatewayv1.Hostname, bool) {
929+
hostnames := make([]gatewayv1.Hostname, 0)
930+
931+
for _, gateway := range gateways {
932+
if gateway.ListenerName != "" {
933+
// If a listener name is specified, only check that listener
934+
for _, listener := range gateway.Gateway.Spec.Listeners {
935+
if string(listener.Name) == gateway.ListenerName {
936+
// If a listener does not specify a hostname, it can match any hostname
937+
if listener.Hostname == nil {
938+
return nil, true
939+
}
940+
hostnames = append(hostnames, *listener.Hostname)
941+
break
942+
}
943+
}
944+
} else {
945+
// Otherwise, check all listeners
946+
for _, listener := range gateway.Gateway.Spec.Listeners {
947+
// Only consider listeners that can effectively configure hostnames (HTTP, HTTPS, or TLS)
948+
if isListenerHostnameEffective(listener) {
949+
if listener.Hostname == nil {
950+
return nil, true
951+
}
952+
hostnames = append(hostnames, *listener.Hostname)
953+
}
954+
}
955+
}
956+
}
957+
958+
return hostnames, false
959+
}
960+
961+
// getMinimumHostnameIntersection returns the smallest intersection hostname
962+
// - If the listener hostname is empty, return the HTTPRoute hostname
963+
// - If the listener hostname is a wildcard of the HTTPRoute hostname, return the HTTPRoute hostname
964+
// - If the HTTPRoute hostname is a wildcard of the listener hostname, return the listener hostname
965+
// - If the HTTPRoute hostname and listener hostname are the same, return it
966+
// - If none of the above, return an empty string
967+
func getMinimumHostnameIntersection(gateways []RouteParentRefContext, hostname gatewayv1.Hostname) gatewayv1.Hostname {
968+
for _, gateway := range gateways {
969+
for _, listener := range gateway.Gateway.Spec.Listeners {
970+
// If a listener name is specified, only check that listener
971+
// If the listener name is not specified, check all listeners
972+
if gateway.ListenerName == "" || gateway.ListenerName == string(listener.Name) {
973+
if listener.Hostname == nil || *listener.Hostname == "" {
974+
return hostname
975+
}
976+
if HostnamesMatch(string(*listener.Hostname), string(hostname)) {
977+
return hostname
978+
}
979+
if HostnamesMatch(string(hostname), string(*listener.Hostname)) {
980+
return *listener.Hostname
981+
}
982+
}
983+
}
984+
}
985+
986+
return ""
987+
}
988+
989+
// isListenerHostnameEffective checks if a listener can specify a hostname to match the hostname in the request
990+
// Basically, check if the listener uses HTTP, HTTPS, or TLS protocol
991+
func isListenerHostnameEffective(listener gatewayv1.Listener) bool {
992+
return listener.Protocol == gatewayv1.HTTPProtocolType ||
993+
listener.Protocol == gatewayv1.HTTPSProtocolType ||
994+
listener.Protocol == gatewayv1.TLSProtocolType
995+
}

0 commit comments

Comments
 (0)