@@ -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