Repository: vmware/load-balancer-and-ingress-services-for-kubernetes
Pull request #1662: AV-231513 HTTPRoute Rewrite Filter
Author: login: pkoshtavmware
Labels: name: enhancement
description: New feature or request
name: open-for-review
description: Pull request is up for review
Created: 2025-02-27T12:02:38Z | Merged: 2025-03-17T05:16:26Z

AV-231513 HTTPRoute Rewrite Filter


Diff:
diff --git a/ako-gateway-api/nodes/avi_model_l7_translator.go b/ako-gateway-api/nodes/avi_model_l7_translator.go
index 0597664f4..9dcee5360 100644
--- a/ako-gateway-api/nodes/avi_model_l7_translator.go
+++ b/ako-gateway-api/nodes/avi_model_l7_translator.go
@@ -353,6 +353,7 @@ func (o *AviObjectGraph) BuildHTTPPolicySet(key string, vsNode *nodes.AviEvhVsNo
 		return
 	}
 	o.BuildHTTPPolicySetHTTPRequestRules(key, httpPSName, vsNode, routeModel, rule.Filters, index)
+	o.BuildHTTPPolicySetHTTPRequestUrlRewriteRules(key, httpPSName, vsNode, routeModel, rule.Filters, index)
 	o.BuildHTTPPolicySetHTTPResponseRules(key, vsNode, routeModel, rule.Filters, index)
 	utils.AviLog.Infof("key: %s, msg: Attached HTTP policies to vs %s", key, vsNode.Name)
 }
@@ -462,3 +463,45 @@ func (o *AviObjectGraph) BuildHTTPPolicySetHTTPRequestRedirectRules(key, httpPSn
 	}
 	return isRedirectPresent
 }
+
+func (o *AviObjectGraph) BuildHTTPPolicySetHTTPRequestUrlRewriteRules(key, httpPSname string, vsNode *nodes.AviEvhVsNode, routeModel RouteModel, filters []*Filter, index int) {
+	urlRewriteAction := &models.HTTPRewriteURLAction{}
+	for _, filter := range filters {
+		// considering only the first reWriteFilter
+		if filter.UrlRewriteFilter != nil {
+			if filter.UrlRewriteFilter.hostname != "" {
+				urlRewriteAction.HostHdr = &models.URIParam{
+					Tokens: []*models.URIParamToken{
+						{
+							StrValue: &filter.UrlRewriteFilter.hostname,
+							Type:     proto.String("URI_TOKEN_TYPE_STRING"),
+						},
+					},
+					Type: proto.String("URI_PARAM_TYPE_TOKENIZED"),
+				}
+			}
+			if filter.UrlRewriteFilter.path != nil {
+				urlRewriteAction.Path = &models.URIParam{
+					Tokens: []*models.URIParamToken{{
+						StrValue: filter.UrlRewriteFilter.path.ReplaceFullPath,
+						Type:     proto.String("URI_TOKEN_TYPE_STRING"),
+					}},
+					Type: proto.String("URI_PARAM_TYPE_TOKENIZED"),
+				}
+			}
+			urlRewriteAction.Query = &models.URIParamQuery{
+				AddString: nil,
+				KeepQuery: proto.Bool(true),
+			}
+
+			if len(vsNode.HttpPolicyRefs[index].RequestRules) == 0 {
+				requestRule := &models.HTTPRequestRule{Name: &httpPSname, Enable: proto.Bool(true), RewriteURLAction: urlRewriteAction, Index: proto.Int32(int32(index + 1))}
+				vsNode.HttpPolicyRefs[index].RequestRules = []*models.HTTPRequestRule{requestRule}
+			} else {
+				vsNode.HttpPolicyRefs[index].RequestRules[0].RewriteURLAction = urlRewriteAction
+			}
+			utils.AviLog.Debugf("key: %s, msg: Attached HTTP request redirect policies %s to vs %s", key, utils.Stringify(vsNode.HttpPolicyRefs[index].RequestRules), vsNode.Name)
+			break
+		}
+	}
+}
diff --git a/ako-gateway-api/nodes/gateway_model_rel.go b/ako-gateway-api/nodes/gateway_model_rel.go
index 764862c80..ab02da433 100644
--- a/ako-gateway-api/nodes/gateway_model_rel.go
+++ b/ako-gateway-api/nodes/gateway_model_rel.go
@@ -677,12 +677,18 @@ func validateReferredHTTPRoute(key, name, namespace string, allowedRoutesAll boo
 				matchNamespace = string(*parentRef.Namespace)
 			}
 			if (parentRef.Name == gatewayv1.ObjectName(name)) && (matchNamespace == namespace) {
-				err := validateParentReference(key, httpRoute, httpRouteStatus, parentRefIndexFromSpec, &parentRefIndexInHttpRouteStatus, &indexInCache)
-				if err != nil {
-					parentRefName := parentRef.Name
-					utils.AviLog.Warnf("key: %s, msg: Parent Reference %s of HTTPRoute object %s is not valid, err: %v", key, parentRefName, httpRoute.Name, err)
+				isValidHttprouteRules := validateHTTPRouteRules(key, httpRoute, httpRouteStatus)
+				if isValidHttprouteRules {
+					err := validateParentReference(key, httpRoute, httpRouteStatus, parentRefIndexFromSpec, &parentRefIndexInHttpRouteStatus, &indexInCache)
+					if err != nil {
+						parentRefName := parentRef.Name
+						utils.AviLog.Warnf("key: %s, msg: Parent Reference %s of HTTPRoute object %s is not valid, err: %v", key, parentRefName, httpRoute.Name, err)
+					} else {
+						appendRoute = true
+					}
 				} else {
-					appendRoute = true
+					utils.AviLog.Warnf("key: %s, msg: HTTPUrlRewrite PathType has Unsupported value.", key)
+					appendRoute = false
 				}
 			} else {
 				gwName := parentRef.Name
diff --git a/ako-gateway-api/nodes/route_model.go b/ako-gateway-api/nodes/route_model.go
index 4e44b87e8..70ad5d346 100644
--- a/ako-gateway-api/nodes/route_model.go
+++ b/ako-gateway-api/nodes/route_model.go
@@ -17,6 +17,7 @@ package nodes
 import (
 	"fmt"
 	"sort"
+	"strings"
 
 	"k8s.io/apimachinery/pkg/util/sets"
 	gatewayv1 "sigs.k8s.io/gateway-api/apis/v1"
@@ -94,11 +95,17 @@ type RedirectFilter struct {
 	StatusCode int32
 }
 
+type HTTPUrlRewriteFilter struct {
+	hostname string
+	path     *gatewayv1.HTTPPathModifier
+}
+
 type Filter struct {
-	Type           string
-	RequestFilter  *HeaderFilter
-	ResponseFilter *HeaderFilter
-	RedirectFilter *RedirectFilter
+	Type             string
+	RequestFilter    *HeaderFilter
+	ResponseFilter   *HeaderFilter
+	RedirectFilter   *RedirectFilter
+	UrlRewriteFilter *HTTPUrlRewriteFilter
 }
 
 type Backend struct {
@@ -282,6 +289,21 @@ func (hr *httpRoute) ParseRouteConfig(key string) *RouteConfig {
 					filter.RedirectFilter.StatusCode = int32(*ruleFilter.RequestRedirect.StatusCode)
 				}
 			}
+
+			// URL rewrite filter
+			if ruleFilter.URLRewrite != nil {
+				filter.UrlRewriteFilter = &HTTPUrlRewriteFilter{}
+				if ruleFilter.URLRewrite.Hostname != nil {
+					filter.UrlRewriteFilter.hostname = string(*ruleFilter.URLRewrite.Hostname)
+				}
+				if ruleFilter.URLRewrite.Path != nil {
+					filter.UrlRewriteFilter.path = ruleFilter.URLRewrite.Path.DeepCopy()
+					if strings.HasPrefix(*filter.UrlRewriteFilter.path.ReplaceFullPath, "/") {
+						*filter.UrlRewriteFilter.path.ReplaceFullPath = (*filter.UrlRewriteFilter.path.ReplaceFullPath)[1:]
+					}
+
+				}
+			}
 			routeConfigRule.Filters = append(routeConfigRule.Filters, filter)
 		}
 		hasInvalidBackend := false
diff --git a/ako-gateway-api/nodes/route_validator.go b/ako-gateway-api/nodes/route_validator.go
index 46bb7fd80..b03baecff 100644
--- a/ako-gateway-api/nodes/route_validator.go
+++ b/ako-gateway-api/nodes/route_validator.go
@@ -52,18 +52,22 @@ func IsHTTPRouteValid(key string, obj *gatewayv1.HTTPRoute) bool {
 	var invalidParentRefCount int
 	parentRefIndexInHttpRouteStatus := 0
 	indexInCache := -1
-	for parentRefIndexFromSpec := range httpRoute.Spec.ParentRefs {
-		err := validateParentReference(key, httpRoute, httpRouteStatus, parentRefIndexFromSpec, &parentRefIndexInHttpRouteStatus, &indexInCache)
-		if err != nil {
-			invalidParentRefCount++
-			parentRefName := httpRoute.Spec.ParentRefs[parentRefIndexFromSpec].Name
-			utils.AviLog.Warnf("key: %s, msg: Parent Reference %s of HTTPRoute object %s is not valid, err: %v", key, parentRefName, httpRoute.Name, err)
+	isValidHttprouteRules := validateHTTPRouteRules(key, httpRoute, httpRouteStatus)
+	if isValidHttprouteRules {
+		for parentRefIndexFromSpec := range httpRoute.Spec.ParentRefs {
+			err := validateParentReference(key, httpRoute, httpRouteStatus, parentRefIndexFromSpec, &parentRefIndexInHttpRouteStatus, &indexInCache)
+			if err != nil {
+				invalidParentRefCount++
+				parentRefName := httpRoute.Spec.ParentRefs[parentRefIndexFromSpec].Name
+				utils.AviLog.Warnf("key: %s, msg: Parent Reference %s of HTTPRoute object %s is not valid, err: %v", key, parentRefName, httpRoute.Name, err)
+			}
 		}
 	}
+
 	akogatewayapistatus.Record(key, httpRoute, &status.Status{HTTPRouteStatus: httpRouteStatus})
 
 	// No valid attachment, we can't proceed with this HTTPRoute object.
-	if invalidParentRefCount == len(httpRoute.Spec.ParentRefs) {
+	if invalidParentRefCount == len(httpRoute.Spec.ParentRefs) || !isValidHttprouteRules {
 		utils.AviLog.Errorf("key: %s, msg: HTTPRoute object %s is not valid", key, httpRoute.Name)
 		akogatewayapilib.AKOControlConfig().EventRecorder().Eventf(httpRoute, corev1.EventTypeWarning,
 			lib.Detached, "HTTPRoute object %s is not valid", httpRoute.Name)
@@ -94,6 +98,63 @@ func validateBackendReference(key string, backend Backend) (bool, akogatewayapis
 	return true, routeConditionResolvedRef
 }
 
+func validateHTTPRouteRules(key string, httpRoute *gatewayv1.HTTPRoute, httpRouteStatus *gatewayv1.HTTPRouteStatus) bool {
+
+	//Validate Filters
+
+	//Validate URL Rewrite Filter
+	if httpRoute.Spec.Rules != nil {
+		for _, rule := range httpRoute.Spec.Rules {
+			for _, filter := range rule.Filters {
+				if filter.Type == gatewayv1.HTTPRouteFilterURLRewrite && filter.URLRewrite != nil && filter.URLRewrite.Path != nil && filter.URLRewrite.Path.Type != gatewayv1.FullPathHTTPPathModifier {
+					for parentRefIndexFromSpec := range httpRoute.Spec.ParentRefs {
+
+						// creates the Parent status only when the AKO is the gateway controller
+						name := string(httpRoute.Spec.ParentRefs[parentRefIndexFromSpec].Name)
+						namespace := httpRoute.Namespace
+						if httpRoute.Spec.ParentRefs[parentRefIndexFromSpec].Namespace != nil {
+							namespace = string(*httpRoute.Spec.ParentRefs[parentRefIndexFromSpec].Namespace)
+						}
+						obj, err := akogatewayapilib.AKOControlConfig().GatewayApiInformers().GatewayInformer.Lister().Gateways(namespace).Get(name)
+						if err != nil {
+							utils.AviLog.Errorf("key: %s, msg: unable to get the gateway object. err: %s", key, err)
+							return false
+						}
+						gateway := obj.DeepCopy()
+
+						gwClass := string(gateway.Spec.GatewayClassName)
+						_, isAKOCtrl := akogatewayapiobjects.GatewayApiLister().IsGatewayClassControllerAKO(gwClass)
+						if !isAKOCtrl {
+							utils.AviLog.Warnf("key: %s, msg: controller for the parent reference %s of HTTPRoute object %s is not ako", key, name, httpRoute.Name)
+							continue
+						}
+
+						httpRouteStatus.Parents = append(httpRouteStatus.Parents, gatewayv1.RouteParentStatus{})
+						httpRouteStatus.Parents[parentRefIndexFromSpec].ControllerName = akogatewayapilib.GatewayController
+						httpRouteStatus.Parents[parentRefIndexFromSpec].ParentRef.Name = gatewayv1.ObjectName(name)
+						httpRouteStatus.Parents[parentRefIndexFromSpec].ParentRef.Namespace = (*gatewayv1.Namespace)(&namespace)
+						if httpRoute.Spec.ParentRefs[parentRefIndexFromSpec].SectionName != nil {
+							httpRouteStatus.Parents[parentRefIndexFromSpec].ParentRef.SectionName = httpRoute.Spec.ParentRefs[parentRefIndexFromSpec].SectionName
+						}
+						routeConditionAccepted := akogatewayapistatus.NewCondition().
+							Type(string(gatewayv1.RouteConditionAccepted)).
+							Status(metav1.ConditionFalse).
+							ObservedGeneration(httpRoute.ObjectMeta.Generation).
+							Reason(string(gatewayv1.RouteReasonUnsupportedValue)).
+							Message("HTTPUrlRewrite PathType has Unsupported value")
+						routeConditionAccepted.SetIn(&httpRouteStatus.Parents[parentRefIndexFromSpec].Conditions)
+					}
+					utils.AviLog.Errorf("key: %s, msg: HTTPUrlRewrite PathType has Unsupported value %s.", key, filter.URLRewrite.Path.Type)
+					return false
+
+				}
+			}
+		}
+	}
+
+	return true
+}
+
 func setResolvedRefConditionInHTTPRouteStatus(key string, routeConditionResolvedRef akogatewayapistatus.Condition, routeTypeNamespaceName string) {
 	if routeConditionResolvedRef == nil {
 		return
diff --git a/tests/gatewayapitests/graphlayer/httproute_test.go b/tests/gatewayapitests/graphlayer/httproute_test.go
index 99e6d12d8..c76e8a894 100644
--- a/tests/gatewayapitests/graphlayer/httproute_test.go
+++ b/tests/gatewayapitests/graphlayer/httproute_test.go
@@ -3046,3 +3046,254 @@ func TestHTTPRouteCRUDWithRegexPath(t *testing.T) {
 	akogatewayapitests.TeardownGateway(t, gatewayName, DEFAULT_NAMESPACE)
 	akogatewayapitests.TeardownGatewayClass(t, gatewayClassName)
 }
+func TestHTTPRouteFilterWithUrlRewrite(t *testing.T) {
+	gatewayName := "gateway-hr-30"
+	gatewayClassName := "gateway-class-hr-30"
+	httpRouteName := "http-route-hr-30"
+	ports := []int32{8080}
+	modelName, _ := akogatewayapitests.GetModelName(DEFAULT_NAMESPACE, gatewayName)
+
+	akogatewayapitests.SetupGatewayClass(t, gatewayClassName, akogatewayapilib.GatewayController)
+	listeners := akogatewayapitests.GetListenersV1(ports, false, false)
+	akogatewayapitests.SetupGateway(t, gatewayName, DEFAULT_NAMESPACE, gatewayClassName, nil, listeners)
+
+	g := gomega.NewGomegaWithT(t)
+	g.Eventually(func() bool {
+		found, _ := objects.SharedAviGraphLister().Get(modelName)
+		return found
+	}, 25*time.Second).Should(gomega.Equal(true))
+
+	parentRefs := akogatewayapitests.GetParentReferencesV1([]string{gatewayName}, DEFAULT_NAMESPACE, ports)
+	rule := akogatewayapitests.GetHTTPRouteRuleV1(integrationtest.PATHPREFIX, []string{"/foo"}, []string{},
+		map[string][]string{"URLRewrite": {}},
+		[][]string{{"avisvc", "default", "8080", "1"}}, nil)
+	rules := []gatewayv1.HTTPRouteRule{rule}
+	hostnames := []gatewayv1.Hostname{"foo-8080.com"}
+	akogatewayapitests.SetupHTTPRoute(t, httpRouteName, DEFAULT_NAMESPACE, parentRefs, hostnames, rules)
+
+	g.Eventually(func() int {
+		found, aviModel := objects.SharedAviGraphLister().Get(modelName)
+		if !found {
+			return 0
+		}
+		nodes := aviModel.(*avinodes.AviObjectGraph).GetAviEvhVS()
+		if len(nodes[0].EvhNodes) == 1 {
+			childVS := nodes[0].EvhNodes[0]
+			if len(childVS.HttpPolicyRefs) != 1 {
+				return -1
+			}
+			return len(childVS.HttpPolicyRefs[0].RequestRules)
+		}
+		return -1
+
+	}, 25*time.Second).Should(gomega.Equal(1))
+	_, aviModel := objects.SharedAviGraphLister().Get(modelName)
+	nodes := aviModel.(*avinodes.AviObjectGraph).GetAviEvhVS()
+	childVS := nodes[0].EvhNodes[0]
+
+	g.Expect(*childVS.HttpPolicyRefs[0].RequestRules[0].Name).To(gomega.Equal(childVS.Name))
+	g.Expect(childVS.HttpPolicyRefs[0].RequestRules[0].RewriteURLAction).ShouldNot(gomega.BeNil())
+	g.Expect(*childVS.HttpPolicyRefs[0].RequestRules[0].RewriteURLAction.HostHdr.Tokens[0].StrValue).To(gomega.Equal("rewrite.com"))
+	g.Expect(*childVS.HttpPolicyRefs[0].RequestRules[0].RewriteURLAction.Path.Tokens[0].StrValue).To(gomega.Equal("bar"))
+
+	//update httproute and combine requestRewrite with other requestHeader modifiers except requestRedirect
+	rule = akogatewayapitests.GetHTTPRouteRuleV1(integrationtest.PATHPREFIX, []string{"/foo"}, []string{},
+		map[string][]string{"URLRewrite": {}, "RequestHeaderModifier": {"add", "remove", "replace"}},
+		[][]string{{"avisvc", "default", "8080", "1"}}, nil)
+	rules = []gatewayv1.HTTPRouteRule{rule}
+	akogatewayapitests.UpdateHTTPRoute(t, httpRouteName, DEFAULT_NAMESPACE, parentRefs, hostnames, rules)
+
+	g.Eventually(func() int {
+		found, aviModel := objects.SharedAviGraphLister().Get(modelName)
+		if !found {
+			return 0
+		}
+		nodes := aviModel.(*avinodes.AviObjectGraph).GetAviEvhVS()
+		if len(nodes[0].EvhNodes) == 1 {
+			childVS := nodes[0].EvhNodes[0]
+			if len(childVS.HttpPolicyRefs) != 1 {
+				return -1
+			}
+			return len(childVS.HttpPolicyRefs[0].RequestRules[0].HdrAction)
+		}
+		return -1
+	}, 25*time.Second).Should(gomega.Equal(3))
+
+	_, aviModel = objects.SharedAviGraphLister().Get(modelName)
+	nodes = aviModel.(*avinodes.AviObjectGraph).GetAviEvhVS()
+	childVS = nodes[0].EvhNodes[0]
+
+	g.Expect(*childVS.HttpPolicyRefs[0].RequestRules[0].Name).To(gomega.Equal(childVS.Name))
+	g.Expect(childVS.HttpPolicyRefs[0].RequestRules[0].RewriteURLAction).ShouldNot(gomega.BeNil())
+	g.Expect(*childVS.HttpPolicyRefs[0].RequestRules[0].RewriteURLAction.HostHdr.Tokens[0].StrValue).To(gomega.Equal("rewrite.com"))
+	g.Expect(*childVS.HttpPolicyRefs[0].RequestRules[0].RewriteURLAction.Path.Tokens[0].StrValue).To(gomega.Equal("bar"))
+	g.Expect(*childVS.HttpPolicyRefs[0].RequestRules[0].HdrAction[0].Action).To(gomega.Equal("HTTP_ADD_HDR"))
+	g.Expect(*childVS.HttpPolicyRefs[0].RequestRules[0].HdrAction[0].Hdr.Name).To(gomega.Equal("new-header"))
+	g.Expect(*childVS.HttpPolicyRefs[0].RequestRules[0].HdrAction[0].Hdr.Value.Val).To(gomega.Equal("any-value"))
+	g.Expect(*childVS.HttpPolicyRefs[0].RequestRules[0].HdrAction[0].HdrIndex).To(gomega.Equal(uint32(0)))
+	g.Expect(*childVS.HttpPolicyRefs[0].RequestRules[0].HdrAction[1].Action).To(gomega.Equal("HTTP_REPLACE_HDR"))
+	g.Expect(*childVS.HttpPolicyRefs[0].RequestRules[0].HdrAction[1].Hdr.Name).To(gomega.Equal("my-header"))
+	g.Expect(*childVS.HttpPolicyRefs[0].RequestRules[0].HdrAction[1].Hdr.Value.Val).To(gomega.Equal("any-value"))
+	g.Expect(*childVS.HttpPolicyRefs[0].RequestRules[0].HdrAction[1].HdrIndex).To(gomega.Equal(uint32(1)))
+	g.Expect(*childVS.HttpPolicyRefs[0].RequestRules[0].HdrAction[2].Action).To(gomega.Equal("HTTP_REMOVE_HDR"))
+	g.Expect(*childVS.HttpPolicyRefs[0].RequestRules[0].HdrAction[2].Hdr.Name).To(gomega.Equal("old-header"))
+	g.Expect(*childVS.HttpPolicyRefs[0].RequestRules[0].HdrAction[2].HdrIndex).To(gomega.Equal(uint32(2)))
+
+	//update httproute to have only rewrite filter
+	rule = akogatewayapitests.GetHTTPRouteRuleV1(integrationtest.PATHPREFIX, []string{"/foo"}, []string{},
+		map[string][]string{"URLRewrite": {}},
+		[][]string{{"avisvc", "default", "8080", "1"}}, nil)
+	rules = []gatewayv1.HTTPRouteRule{rule}
+	akogatewayapitests.UpdateHTTPRoute(t, httpRouteName, DEFAULT_NAMESPACE, parentRefs, hostnames, rules)
+
+	g.Eventually(func() int {
+		found, aviModel := objects.SharedAviGraphLister().Get(modelName)
+		if !found {
+			return 0
+		}
+		nodes := aviModel.(*avinodes.AviObjectGraph).GetAviEvhVS()
+		if len(nodes[0].EvhNodes) == 1 {
+			childVS := nodes[0].EvhNodes[0]
+			if len(childVS.HttpPolicyRefs) != 1 {
+				return -1
+			}
+			return len(childVS.HttpPolicyRefs[0].RequestRules[0].HdrAction)
+		}
+		return -1
+	}, 25*time.Second).Should(gomega.Equal(0))
+
+	_, aviModel = objects.SharedAviGraphLister().Get(modelName)
+	nodes = aviModel.(*avinodes.AviObjectGraph).GetAviEvhVS()
+	childVS = nodes[0].EvhNodes[0]
+
+	g.Expect(*childVS.HttpPolicyRefs[0].RequestRules[0].Name).To(gomega.Equal(childVS.Name))
+	g.Expect(childVS.HttpPolicyRefs[0].RequestRules[0].HdrAction).Should(gomega.BeNil())
+	g.Expect(childVS.HttpPolicyRefs[0].RequestRules[0].RewriteURLAction).ShouldNot(gomega.BeNil())
+	g.Expect(*childVS.HttpPolicyRefs[0].RequestRules[0].RewriteURLAction.HostHdr.Tokens[0].StrValue).To(gomega.Equal("rewrite.com"))
+	g.Expect(*childVS.HttpPolicyRefs[0].RequestRules[0].RewriteURLAction.Path.Tokens[0].StrValue).To(gomega.Equal("bar"))
+
+	// update httproute to remove all the filters
+	rule = akogatewayapitests.GetHTTPRouteRuleV1(integrationtest.PATHPREFIX, []string{"/foo"}, []string{},
+		map[string][]string{},
+		[][]string{{"avisvc", "default", "8080", "1"}}, nil)
+	rules = []gatewayv1.HTTPRouteRule{rule}
+	akogatewayapitests.UpdateHTTPRoute(t, httpRouteName, DEFAULT_NAMESPACE, parentRefs, hostnames, rules)
+
+	g.Eventually(func() int {
+		_, aviModel := objects.SharedAviGraphLister().Get(modelName)
+		nodes := aviModel.(*avinodes.AviObjectGraph).GetAviEvhVS()
+		childVS := nodes[0].EvhNodes[0]
+		return len(childVS.HttpPolicyRefs)
+	}, 25*time.Second).Should(gomega.Equal(0))
+
+	// delete httproute
+	akogatewayapitests.TeardownHTTPRoute(t, httpRouteName, DEFAULT_NAMESPACE)
+	akogatewayapitests.TeardownGateway(t, gatewayName, DEFAULT_NAMESPACE)
+	akogatewayapitests.TeardownGatewayClass(t, gatewayClassName)
+}
+
+func TestHTTPRouteFilterWithUrlRewriteOnlyHostnameOrPath(t *testing.T) {
+	gatewayName := "gateway-hr-30"
+	gatewayClassName := "gateway-class-hr-30"
+	httpRouteName := "http-route-hr-30"
+	ports := []int32{8080}
+	modelName, _ := akogatewayapitests.GetModelName(DEFAULT_NAMESPACE, gatewayName)
+
+	akogatewayapitests.SetupGatewayClass(t, gatewayClassName, akogatewayapilib.GatewayController)
+	listeners := akogatewayapitests.GetListenersV1(ports, false, false)
+	akogatewayapitests.SetupGateway(t, gatewayName, DEFAULT_NAMESPACE, gatewayClassName, nil, listeners)
+
+	g := gomega.NewGomegaWithT(t)
+	g.Eventually(func() bool {
+		found, _ := objects.SharedAviGraphLister().Get(modelName)
+		return found
+	}, 25*time.Second).Should(gomega.Equal(true))
+
+	parentRefs := akogatewayapitests.GetParentReferencesV1([]string{gatewayName}, DEFAULT_NAMESPACE, ports)
+	rule := akogatewayapitests.GetHTTPRouteRuleV1(integrationtest.PATHPREFIX, []string{"/foo"}, []string{},
+		map[string][]string{"URLRewrite": {}},
+		[][]string{{"avisvc", "default", "8080", "1"}}, nil)
+	rules := []gatewayv1.HTTPRouteRule{rule}
+
+	//Setting the hostname to be nil
+	rules[0].Filters[0].URLRewrite.Hostname = nil
+	hostnames := []gatewayv1.Hostname{"foo-8080.com"}
+	akogatewayapitests.SetupHTTPRoute(t, httpRouteName, DEFAULT_NAMESPACE, parentRefs, hostnames, rules)
+
+	g.Eventually(func() int {
+		found, aviModel := objects.SharedAviGraphLister().Get(modelName)
+		if !found || aviModel == nil {
+			return 0
+		}
+		nodes := aviModel.(*avinodes.AviObjectGraph).GetAviEvhVS()
+		if len(nodes[0].EvhNodes) == 1 {
+			childVS := nodes[0].EvhNodes[0]
+			if len(childVS.HttpPolicyRefs) != 1 {
+				return -1
+			}
+			return len(childVS.HttpPolicyRefs[0].RequestRules)
+
+		}
+		return -1
+	}, 25*time.Second).Should(gomega.Equal(1))
+
+	_, aviModel := objects.SharedAviGraphLister().Get(modelName)
+	nodes := aviModel.(*avinodes.AviObjectGraph).GetAviEvhVS()
+	childVS := nodes[0].EvhNodes[0]
+
+	g.Expect(*childVS.HttpPolicyRefs[0].RequestRules[0].Name).To(gomega.Equal(childVS.Name))
+	g.Expect(childVS.HttpPolicyRefs[0].RequestRules[0].RewriteURLAction).ShouldNot(gomega.BeNil())
+	g.Expect(childVS.HttpPolicyRefs[0].RequestRules[0].RewriteURLAction.HostHdr).To(gomega.BeNil())
+	g.Expect(*childVS.HttpPolicyRefs[0].RequestRules[0].RewriteURLAction.Path.Tokens[0].StrValue).To(gomega.Equal("bar"))
+
+	//Setting the path to be nil
+	rules[0].Filters[0].URLRewrite.Path = nil
+	host := "rewrite.com"
+	rules[0].Filters[0].URLRewrite.Hostname = (*gatewayv1.PreciseHostname)(&host)
+	akogatewayapitests.UpdateHTTPRoute(t, httpRouteName, DEFAULT_NAMESPACE, parentRefs, hostnames, rules)
+
+	g.Eventually(func() bool {
+		found, aviModel := objects.SharedAviGraphLister().Get(modelName)
+		if !found {
+			return false
+		}
+		nodes := aviModel.(*avinodes.AviObjectGraph).GetAviEvhVS()
+		if len(nodes[0].EvhNodes) == 1 {
+			childVS := nodes[0].EvhNodes[0]
+			if len(childVS.HttpPolicyRefs) != 1 {
+				return false
+			}
+			return childVS.HttpPolicyRefs[0].RequestRules[0].RewriteURLAction != nil && childVS.HttpPolicyRefs[0].RequestRules[0].RewriteURLAction.Path == nil
+		}
+		return false
+	}, 25*time.Second).Should(gomega.Equal(true))
+
+	_, aviModel = objects.SharedAviGraphLister().Get(modelName)
+	nodes = aviModel.(*avinodes.AviObjectGraph).GetAviEvhVS()
+	childVS = nodes[0].EvhNodes[0]
+
+	g.Expect(*childVS.HttpPolicyRefs[0].RequestRules[0].Name).To(gomega.Equal(childVS.Name))
+	g.Expect(childVS.HttpPolicyRefs[0].RequestRules[0].RewriteURLAction).ShouldNot(gomega.BeNil())
+	g.Expect(*childVS.HttpPolicyRefs[0].RequestRules[0].RewriteURLAction.HostHdr.Tokens[0].StrValue).To(gomega.Equal("rewrite.com"))
+	g.Expect(childVS.HttpPolicyRefs[0].RequestRules[0].RewriteURLAction.Path).To(gomega.BeNil())
+	akogatewayapitests.UpdateHTTPRoute(t, httpRouteName, DEFAULT_NAMESPACE, parentRefs, hostnames, rules)
+
+	// update httproute to remove all the filters
+	rule = akogatewayapitests.GetHTTPRouteRuleV1(integrationtest.PATHPREFIX, []string{"/foo"}, []string{},
+		map[string][]string{},
+		[][]string{{"avisvc", "default", "8080", "1"}}, nil)
+	rules = []gatewayv1.HTTPRouteRule{rule}
+	akogatewayapitests.UpdateHTTPRoute(t, httpRouteName, DEFAULT_NAMESPACE, parentRefs, hostnames, rules)
+
+	g.Eventually(func() int {
+		_, aviModel := objects.SharedAviGraphLister().Get(modelName)
+		nodes := aviModel.(*avinodes.AviObjectGraph).GetAviEvhVS()
+		childVS := nodes[0].EvhNodes[0]
+		return len(childVS.HttpPolicyRefs)
+	}, 25*time.Second).Should(gomega.Equal(0))
+
+	// delete httproute
+	akogatewayapitests.TeardownHTTPRoute(t, httpRouteName, DEFAULT_NAMESPACE)
+	akogatewayapitests.TeardownGateway(t, gatewayName, DEFAULT_NAMESPACE)
+	akogatewayapitests.TeardownGatewayClass(t, gatewayClassName)
+}
diff --git a/tests/gatewayapitests/ingestion/httproute_test.go b/tests/gatewayapitests/ingestion/httproute_test.go
index d6beb4deb..0e7d8c7c7 100644
--- a/tests/gatewayapitests/ingestion/httproute_test.go
+++ b/tests/gatewayapitests/ingestion/httproute_test.go
@@ -290,3 +290,50 @@ func TestHTTPRouteGatewayWithRegexPath(t *testing.T) {
 	akogatewayapitests.TeardownGatewayClass(t, gatewayClassName)
 	waitAndverify(t, gwClassKey)
 }
+
+func TestHTTPRouteFilterWithUrlRewrite(t *testing.T) {
+	gatewayClassName := "gateway-class-08"
+	gatewayName := "gateway-08"
+	httpRouteName := "httproute-08"
+	gwKey := "Gateway/" + DEFAULT_NAMESPACE + "/" + gatewayName
+	gwClassKey := "GatewayClass/" + gatewayClassName
+	namespace := "default"
+	ports := []int32{8080}
+	key := "HTTPRoute" + "/" + namespace + "/" + httpRouteName
+
+	// gatewayclass
+	akogatewayapiobjects.GatewayApiLister().UpdateGatewayClass(gatewayClassName, true)
+	akogatewayapitests.SetupGatewayClass(t, gatewayClassName, akogatewayapilib.GatewayController)
+	t.Logf("Created GatewayClass %s", gatewayClassName)
+	waitAndverify(t, gwClassKey)
+
+	// Gateway without hostname
+	listeners := akogatewayapitests.GetListenersV1(ports, true, false)
+	akogatewayapitests.SetupGateway(t, gatewayName, namespace, gatewayClassName, nil, listeners)
+	t.Logf("Created Gateway %s", gatewayName)
+	waitAndverify(t, gwKey)
+
+	t.Logf("Now creating httproute")
+	parentRefs := akogatewayapitests.GetParentReferencesV1([]string{gatewayName}, namespace, ports)
+	hostnames := []gatewayv1.Hostname{"foo-8080.com"}
+
+	rule := akogatewayapitests.GetHTTPRouteRuleV1(integrationtest.PATHPREFIX, []string{"/foo"}, []string{},
+		map[string][]string{"URLRewrite": {}},
+		[][]string{{"avisvc", "default", "8080", "1"}}, nil)
+	rules := []gatewayv1.HTTPRouteRule{rule}
+	akogatewayapitests.SetupHTTPRoute(t, httpRouteName, namespace, parentRefs, hostnames, rules)
+	waitAndverify(t, key)
+
+	//httproute with invalid rewrite filter configuration
+	rules[0].Filters[0].URLRewrite.Path.Type = gatewayv1.PrefixMatchHTTPPathModifier
+	akogatewayapitests.UpdateHTTPRoute(t, httpRouteName, namespace, parentRefs, hostnames, rules)
+	waitAndverify(t, key)
+
+	// delete
+	akogatewayapitests.TeardownHTTPRoute(t, httpRouteName, namespace)
+	waitAndverify(t, key)
+	akogatewayapitests.TeardownGateway(t, gatewayName, DEFAULT_NAMESPACE)
+	waitAndverify(t, gwKey)
+	akogatewayapitests.TeardownGatewayClass(t, gatewayClassName)
+	waitAndverify(t, gwClassKey)
+}
diff --git a/tests/gatewayapitests/status/httproute_test.go b/tests/gatewayapitests/status/httproute_test.go
index 3dbe31bf5..fbc233881 100644
--- a/tests/gatewayapitests/status/httproute_test.go
+++ b/tests/gatewayapitests/status/httproute_test.go
@@ -1249,3 +1249,69 @@ func TestHTTPRouteGatewayWithEmptyHostnameInGatewayHTTPRoute(t *testing.T) {
 	akogatewayapitests.TeardownGateway(t, gatewayName, DEFAULT_NAMESPACE)
 	akogatewayapitests.TeardownGatewayClass(t, gatewayClassName)
 }
+func TestHTTPRouteFilterWithUnsupportedUrlRewritePathType(t *testing.T) {
+
+	gatewayName := "gateway-hr-19"
+	gatewayClassName := "gateway-class-hr-19"
+	httpRouteName := "http-route-hr-19"
+	svcName := "avisvc-hr-19"
+	namespace := "default"
+	ports := []int32{8080}
+
+	modelName, _ := akogatewayapitests.GetModelName(namespace, gatewayName)
+	akogatewayapitests.SetupGatewayClass(t, gatewayClassName, akogatewayapilib.GatewayController)
+	listeners := akogatewayapitests.GetListenersV1(ports, false, false)
+	akogatewayapitests.SetupGateway(t, gatewayName, namespace, gatewayClassName, nil, listeners)
+	g := gomega.NewGomegaWithT(t)
+
+	g.Eventually(func() bool {
+		found, _ := objects.SharedAviGraphLister().Get(modelName)
+		return found
+	}, 5*time.Second).Should(gomega.Equal(true))
+
+	parentRefs := akogatewayapitests.GetParentReferencesV1([]string{gatewayName}, namespace, ports)
+	rule := akogatewayapitests.GetHTTPRouteRuleV1(integrationtest.PATHPREFIX, []string{"/foo"}, []string{},
+		map[string][]string{"URLRewrite": {}},
+		[][]string{{svcName, "default", "8080", "1"}}, nil)
+	rule.Filters[0].URLRewrite.Path.Type = gatewayv1.PrefixMatchHTTPPathModifier
+	rules := []gatewayv1.HTTPRouteRule{rule}
+	hostnames := []gatewayv1.Hostname{"foo-8080.com"}
+	akogatewayapitests.SetupHTTPRoute(t, httpRouteName, namespace, parentRefs, hostnames, rules)
+
+	g.Eventually(func() bool {
+		httpRoute, err := akogatewayapitests.GatewayClient.GatewayV1().HTTPRoutes(namespace).Get(context.TODO(), httpRouteName, metav1.GetOptions{})
+		if err != nil || httpRoute == nil {
+			t.Logf("Couldn't get the HTTPRoute, err: %+v", err)
+			return false
+		}
+		if len(httpRoute.Status.Parents) != 1 {
+			return false
+		}
+		return apimeta.FindStatusCondition(httpRoute.Status.Parents[0].Conditions, string(gatewayv1.RouteConditionAccepted)) != nil
+	}, 30*time.Second).Should(gomega.Equal(true))
+
+	conditionMap := make(map[string][]metav1.Condition)
+
+	for _, port := range ports {
+		conditions := make([]metav1.Condition, 0, 1)
+		condition := metav1.Condition{
+			Type:    string(gatewayv1.RouteConditionAccepted),
+			Reason:  string(gatewayv1.RouteReasonUnsupportedValue),
+			Status:  metav1.ConditionFalse,
+			Message: "HTTPUrlRewrite PathType has Unsupported value",
+		}
+		conditions = append(conditions, condition)
+		conditionMap[fmt.Sprintf("%s-%d", gatewayName, port)] = conditions
+	}
+	expectedRouteStatus := akogatewayapitests.GetRouteStatusV1([]string{gatewayName}, namespace, ports, conditionMap)
+
+	httpRoute, err := akogatewayapitests.GatewayClient.GatewayV1().HTTPRoutes(namespace).Get(context.TODO(), httpRouteName, metav1.GetOptions{})
+	if err != nil || httpRoute == nil {
+		t.Fatalf("Couldn't get the HTTPRoute, err: %+v", err)
+	}
+	akogatewayapitests.ValidateHTTPRouteStatus(t, &httpRoute.Status, &gatewayv1.HTTPRouteStatus{RouteStatus: *expectedRouteStatus})
+
+	akogatewayapitests.TeardownHTTPRoute(t, httpRouteName, namespace)
+	akogatewayapitests.TeardownGateway(t, gatewayName, DEFAULT_NAMESPACE)
+	akogatewayapitests.TeardownGatewayClass(t, gatewayClassName)
+}
diff --git a/tests/gatewayapitests/utils.go b/tests/gatewayapitests/utils.go
index 3f57234d7..a413aaf97 100644
--- a/tests/gatewayapitests/utils.go
+++ b/tests/gatewayapitests/utils.go
@@ -530,6 +530,16 @@ func GetHTTPRouteFilterV1(filterType string, actions []string) gatewayv1.HTTPRou
 			Hostname:   (*gatewayv1.PreciseHostname)(&host),
 			StatusCode: &statusCode302,
 		}
+	case "URLRewrite":
+		replaceFullPath := "/bar"
+		host := "rewrite.com"
+		routeFilter.URLRewrite = &gatewayv1.HTTPURLRewriteFilter{
+			Hostname: (*gatewayv1.PreciseHostname)(&host),
+			Path: &gatewayv1.HTTPPathModifier{
+				Type:            gatewayv1.FullPathHTTPPathModifier,
+				ReplaceFullPath: &replaceFullPath,
+			},
+		}
 	}
 	return routeFilter
 }


Reviews:
user: login: akshayhavile
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-03-04T06:21:11Z
user: login: pkoshtavmware
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-03-05T10:01:44Z
user: login: pkoshtavmware
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-03-05T10:01:57Z
user: login: akshayhavile
body: @pkoshtavmware Changes looks good to me. 
We should add few test cases:
1. Ingestion test case to validate urlRewrite (This will validate our Validation logic)
2. GraphLayer test case/ FT test cases where we only mention one of the urlrewrite filter (hostname/path) and check what is the behaviour.
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-03-06T06:02:12Z
user: login: akshayhavile
body: Changes LGTM with one minor comment.
state: CHANGES_REQUESTED
author_association: CONTRIBUTOR
submitted_at: 2025-03-11T08:35:06Z
user: login: pkoshtavmware
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-03-13T06:25:46Z
user: login: akshayhavile
body: LGTM. 
state: DISMISSED
author_association: CONTRIBUTOR
submitted_at: 2025-03-13T08:05:09Z
user: login: akshayhavile
state: APPROVED
author_association: CONTRIBUTOR
submitted_at: 2025-03-17T04:22:44Z
user: login: arihantg
body: LGTM
state: APPROVED
author_association: CONTRIBUTOR
submitted_at: 2025-03-17T05:08:20Z

Review comments:
diff_hunk: @@ -350,6 +350,13 @@ func (o *AviObjectGraph) BuildHTTPPolicySet(key string, vsNode *nodes.AviEvhVsNo
 		utils.AviLog.Infof("key: %s, msg: Attached HTTP redirect policy to vs %s", key, vsNode.Name)
 		return
 	}
+	isUrlRewritePresent := o.BuildHTTPPolicySetHTTPRequestUrlRewriteRules(key, httpPSName, vsNode, routeModel, rule.Filters, index)
+	if isUrlRewritePresent {
path: ako-gateway-api/nodes/avi_model_l7_translator.go
user: login: akshayhavile
body: RequestHeader and ResposeHeader modifier add, remove, modify headers of request / response. URLRewriteFilter works on path and hostname. These filters seems to be compatible with each other. Do we want to skip processing those? 
created_at: 2025-03-04T05:06:39Z
author_association: CONTRIBUTOR
diff_hunk: @@ -460,3 +467,39 @@ func (o *AviObjectGraph) BuildHTTPPolicySetHTTPRequestRedirectRules(key, httpPSn
 	}
 	return isRedirectPresent
 }
+
+func (o *AviObjectGraph) BuildHTTPPolicySetHTTPRequestUrlRewriteRules(key, httpPSname string, vsNode *nodes.AviEvhVsNode, routeModel RouteModel, filters []*Filter, index int) bool {
+	urlRewriteAction := &models.HTTPRewriteURLAction{}
+	isUrlRewritePresent := false
path: ako-gateway-api/nodes/avi_model_l7_translator.go
user: login: akshayhavile
body: Nit: We can avoid this variable by returning true or false.
created_at: 2025-03-04T06:13:53Z
author_association: CONTRIBUTOR
diff_hunk: @@ -52,18 +52,22 @@ func IsHTTPRouteValid(key string, obj *gatewayv1.HTTPRoute) bool {
 	var invalidParentRefCount int
 	parentRefIndexInHttpRouteStatus := 0
 	indexInCache := -1
-	for parentRefIndexFromSpec := range httpRoute.Spec.ParentRefs {
-		err := validateParentReference(key, httpRoute, httpRouteStatus, parentRefIndexFromSpec, &parentRefIndexInHttpRouteStatus, &indexInCache)
-		if err != nil {
-			invalidParentRefCount++
-			parentRefName := httpRoute.Spec.ParentRefs[parentRefIndexFromSpec].Name
-			utils.AviLog.Warnf("key: %s, msg: Parent Reference %s of HTTPRoute object %s is not valid, err: %v", key, parentRefName, httpRoute.Name, err)
+	isValidHttprouteRules := validateHTTPRouteRules(key, httpRoute, httpRouteStatus)
+	if isValidHttprouteRules {
+		for parentRefIndexFromSpec := range httpRoute.Spec.ParentRefs {
+			err := validateParentReference(key, httpRoute, httpRouteStatus, parentRefIndexFromSpec, &parentRefIndexInHttpRouteStatus, &indexInCache)
+			if err != nil {
+				invalidParentRefCount++
+				parentRefName := httpRoute.Spec.ParentRefs[parentRefIndexFromSpec].Name
+				utils.AviLog.Warnf("key: %s, msg: Parent Reference %s of HTTPRoute object %s is not valid, err: %v", key, parentRefName, httpRoute.Name, err)
+			}
 		}
 	}
+
 	akogatewayapistatus.Record(key, httpRoute, &status.Status{HTTPRouteStatus: httpRouteStatus})
 
 	// No valid attachment, we can't proceed with this HTTPRoute object.
-	if invalidParentRefCount == len(httpRoute.Spec.ParentRefs) {
+	if invalidParentRefCount == len(httpRoute.Spec.ParentRefs) || !isValidHttprouteRules {
path: ako-gateway-api/nodes/route_validator.go
user: login: akshayhavile
body: GatewayAPI docs suggested instead of rejecting whole route , implementation should set route as partiallyInvalid.
https://gateway-api.sigs.k8s.io/reference/spec/#gateway.networking.k8s.io/v1.HTTPRouteRule 
```To reject an invalid combination or order of filters, implementations SHOULD consider the Route Rules with this configuration invalid. If all Route Rules in a Route are invalid, the entire Route would be considered invalid. If only a portion of Route Rules are invalid, implementations MUST set the “PartiallyInvalid” condition for the Route.```

Can we consider this?

created_at: 2025-03-04T06:19:18Z
author_association: CONTRIBUTOR
diff_hunk: @@ -350,6 +350,13 @@ func (o *AviObjectGraph) BuildHTTPPolicySet(key string, vsNode *nodes.AviEvhVsNo
 		utils.AviLog.Infof("key: %s, msg: Attached HTTP redirect policy to vs %s", key, vsNode.Name)
 		return
 	}
+	isUrlRewritePresent := o.BuildHTTPPolicySetHTTPRequestUrlRewriteRules(key, httpPSName, vsNode, routeModel, rule.Filters, index)
+	if isUrlRewritePresent {
path: ako-gateway-api/nodes/avi_model_l7_translator.go
user: login: pkoshtavmware
body: It was an older code. Have updated the recent code without skipping
created_at: 2025-03-05T10:01:44Z
author_association: CONTRIBUTOR
diff_hunk: @@ -460,3 +467,39 @@ func (o *AviObjectGraph) BuildHTTPPolicySetHTTPRequestRedirectRules(key, httpPSn
 	}
 	return isRedirectPresent
 }
+
+func (o *AviObjectGraph) BuildHTTPPolicySetHTTPRequestUrlRewriteRules(key, httpPSname string, vsNode *nodes.AviEvhVsNode, routeModel RouteModel, filters []*Filter, index int) bool {
+	urlRewriteAction := &models.HTTPRewriteURLAction{}
+	isUrlRewritePresent := false
path: ako-gateway-api/nodes/avi_model_l7_translator.go
user: login: pkoshtavmware
body: Removed the variable altogether
created_at: 2025-03-05T10:01:57Z
author_association: CONTRIBUTOR
diff_hunk: @@ -52,18 +52,22 @@ func IsHTTPRouteValid(key string, obj *gatewayv1.HTTPRoute) bool {
 	var invalidParentRefCount int
 	parentRefIndexInHttpRouteStatus := 0
 	indexInCache := -1
-	for parentRefIndexFromSpec := range httpRoute.Spec.ParentRefs {
-		err := validateParentReference(key, httpRoute, httpRouteStatus, parentRefIndexFromSpec, &parentRefIndexInHttpRouteStatus, &indexInCache)
-		if err != nil {
-			invalidParentRefCount++
-			parentRefName := httpRoute.Spec.ParentRefs[parentRefIndexFromSpec].Name
-			utils.AviLog.Warnf("key: %s, msg: Parent Reference %s of HTTPRoute object %s is not valid, err: %v", key, parentRefName, httpRoute.Name, err)
+	isValidHttprouteRules := validateHTTPRouteRules(key, httpRoute, httpRouteStatus)
+	if isValidHttprouteRules {
+		for parentRefIndexFromSpec := range httpRoute.Spec.ParentRefs {
+			err := validateParentReference(key, httpRoute, httpRouteStatus, parentRefIndexFromSpec, &parentRefIndexInHttpRouteStatus, &indexInCache)
+			if err != nil {
+				invalidParentRefCount++
+				parentRefName := httpRoute.Spec.ParentRefs[parentRefIndexFromSpec].Name
+				utils.AviLog.Warnf("key: %s, msg: Parent Reference %s of HTTPRoute object %s is not valid, err: %v", key, parentRefName, httpRoute.Name, err)
+			}
 		}
 	}
+
 	akogatewayapistatus.Record(key, httpRoute, &status.Status{HTTPRouteStatus: httpRouteStatus})
 
 	// No valid attachment, we can't proceed with this HTTPRoute object.
-	if invalidParentRefCount == len(httpRoute.Spec.ParentRefs) {
+	if invalidParentRefCount == len(httpRoute.Spec.ParentRefs) || !isValidHttprouteRules {
path: ako-gateway-api/nodes/route_validator.go
user: login: akshayhavile
body: We will consider this later.
created_at: 2025-03-06T05:16:50Z
author_association: CONTRIBUTOR
diff_hunk: @@ -3046,3 +3046,268 @@ func TestHTTPRouteCRUDWithRegexPath(t *testing.T) {
 	akogatewayapitests.TeardownGateway(t, gatewayName, DEFAULT_NAMESPACE)
 	akogatewayapitests.TeardownGatewayClass(t, gatewayClassName)
 }
+func TestHTTPRouteFilterWithUrlRewrite(t *testing.T) {
+	gatewayName := "gateway-hr-30"
+	gatewayClassName := "gateway-class-hr-30"
+	httpRouteName := "http-route-hr-30"
+	ports := []int32{8080}
+	modelName, _ := akogatewayapitests.GetModelName(DEFAULT_NAMESPACE, gatewayName)
+
+	akogatewayapitests.SetupGatewayClass(t, gatewayClassName, akogatewayapilib.GatewayController)
+	listeners := akogatewayapitests.GetListenersV1(ports, false, false)
+	akogatewayapitests.SetupGateway(t, gatewayName, DEFAULT_NAMESPACE, gatewayClassName, nil, listeners)
+
+	g := gomega.NewGomegaWithT(t)
+	g.Eventually(func() bool {
+		found, _ := objects.SharedAviGraphLister().Get(modelName)
+		return found
+	}, 25*time.Second).Should(gomega.Equal(true))
+
+	parentRefs := akogatewayapitests.GetParentReferencesV1([]string{gatewayName}, DEFAULT_NAMESPACE, ports)
+	rule := akogatewayapitests.GetHTTPRouteRuleV1(integrationtest.PATHPREFIX, []string{"/foo"}, []string{},
+		map[string][]string{"URLRewrite": {}},
+		[][]string{{"avisvc", "default", "8080", "1"}}, nil)
+	rules := []gatewayv1.HTTPRouteRule{rule}
+	hostnames := []gatewayv1.Hostname{"foo-8080.com"}
+	akogatewayapitests.SetupHTTPRoute(t, httpRouteName, DEFAULT_NAMESPACE, parentRefs, hostnames, rules)
+
+	g.Eventually(func() int {
+		found, aviModel := objects.SharedAviGraphLister().Get(modelName)
+		if !found {
+			return 0
+		}
+		nodes := aviModel.(*avinodes.AviObjectGraph).GetAviEvhVS()
+		return len(nodes[0].EvhNodes)
+	}, 25*time.Second).Should(gomega.Equal(1))
+
+	g.Eventually(func() int {
path: tests/gatewayapitests/graphlayer/httproute_test.go
user: login: akshayhavile
body: Can we combine this `eventually` code logic with logic present at 3074?
created_at: 2025-03-11T08:16:56Z
author_association: CONTRIBUTOR
diff_hunk: @@ -3046,3 +3046,268 @@ func TestHTTPRouteCRUDWithRegexPath(t *testing.T) {
 	akogatewayapitests.TeardownGateway(t, gatewayName, DEFAULT_NAMESPACE)
 	akogatewayapitests.TeardownGatewayClass(t, gatewayClassName)
 }
+func TestHTTPRouteFilterWithUrlRewrite(t *testing.T) {
+	gatewayName := "gateway-hr-30"
+	gatewayClassName := "gateway-class-hr-30"
+	httpRouteName := "http-route-hr-30"
+	ports := []int32{8080}
+	modelName, _ := akogatewayapitests.GetModelName(DEFAULT_NAMESPACE, gatewayName)
+
+	akogatewayapitests.SetupGatewayClass(t, gatewayClassName, akogatewayapilib.GatewayController)
+	listeners := akogatewayapitests.GetListenersV1(ports, false, false)
+	akogatewayapitests.SetupGateway(t, gatewayName, DEFAULT_NAMESPACE, gatewayClassName, nil, listeners)
+
+	g := gomega.NewGomegaWithT(t)
+	g.Eventually(func() bool {
+		found, _ := objects.SharedAviGraphLister().Get(modelName)
+		return found
+	}, 25*time.Second).Should(gomega.Equal(true))
+
+	parentRefs := akogatewayapitests.GetParentReferencesV1([]string{gatewayName}, DEFAULT_NAMESPACE, ports)
+	rule := akogatewayapitests.GetHTTPRouteRuleV1(integrationtest.PATHPREFIX, []string{"/foo"}, []string{},
+		map[string][]string{"URLRewrite": {}},
+		[][]string{{"avisvc", "default", "8080", "1"}}, nil)
+	rules := []gatewayv1.HTTPRouteRule{rule}
+	hostnames := []gatewayv1.Hostname{"foo-8080.com"}
+	akogatewayapitests.SetupHTTPRoute(t, httpRouteName, DEFAULT_NAMESPACE, parentRefs, hostnames, rules)
+
+	g.Eventually(func() int {
+		found, aviModel := objects.SharedAviGraphLister().Get(modelName)
+		if !found {
+			return 0
+		}
+		nodes := aviModel.(*avinodes.AviObjectGraph).GetAviEvhVS()
+		return len(nodes[0].EvhNodes)
+	}, 25*time.Second).Should(gomega.Equal(1))
+
+	g.Eventually(func() int {
path: tests/gatewayapitests/graphlayer/httproute_test.go
user: login: pkoshtavmware
body: Done
created_at: 2025-03-13T06:25:46Z
author_association: CONTRIBUTOR

PR comments:
user: login: pkoshtavmware
created_at: 2025-03-09T04:58:13Z
body: > @pkoshtavmware Changes looks good to me. We should add few test cases:
> 
> 1. Ingestion test case to validate urlRewrite (This will validate our Validation logic)
> 2. GraphLayer test case/ FT test cases where we only mention one of the urlrewrite filter (hostname/path) and check what is the behaviour.

@akshayhavile Added unit testcases in ingestion graph and status layer. However, validation is added in the status layer since we have recently moved httproute validation to ingestion layer
author_association: CONTRIBUTOR
user: login: pkoshtavmware
created_at: 2025-03-09T05:19:46Z
body: build ako
author_association: CONTRIBUTOR
user: login: pkoshtavmware
created_at: 2025-03-10T18:23:55Z
body: build ako
author_association: CONTRIBUTOR
user: login: akshayhavile
created_at: 2025-03-11T08:34:41Z
body: build ako
author_association: CONTRIBUTOR
user: login: pkoshtavmware
created_at: 2025-03-13T10:01:38Z
body: build ako
author_association: CONTRIBUTOR
user: login: pkoshtavmware
created_at: 2025-03-13T11:59:20Z
body: build ako
author_association: CONTRIBUTOR