Repository: envoyproxy/gateway
Pull request #4287 (2024-09-19 20:39:25)

benchmark: test for 1000 HTTPRoutes

codecov[bot]: ## [Codecov](https://app.codecov.io/gh/envoyproxy/gateway/pull/4287?dropdown=coverage&src=pr&el=h1&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=envoyproxy) Report
All modified and coverable lines are covered by tests :white_check_mark:
> Project coverage is 65.69%. Comparing base [(`9cf7828`)](https://app.codecov.io/gh/envoyproxy/gateway/commit/9cf7828d678135f8da9cac97a0b14a6b71077467?dropdown=coverage&el=desc&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=envoyproxy) to head [(`ab4b1ab`)](https://app.codecov.io/gh/envoyproxy/gateway/commit/ab4b1abb5748a5bc801ba245f8087f6822856af1?dropdown=coverage&el=desc&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=envoyproxy).
> Report is 1 commits behind head on main.

<details><summary>Additional details and impacted files</summary>


```diff
@@            Coverage Diff             @@
##             main    #4287      +/-   ##
==========================================
+ Coverage   65.62%   65.69%   +0.07%     
==========================================
  Files         197      197              
  Lines       23540    23555      +15     
==========================================
+ Hits        15448    15475      +27     
+ Misses       6982     6972      -10     
+ Partials     1110     1108       -2     
```

</details>

[:umbrella: View full report in Codecov by Sentry](https://app.codecov.io/gh/envoyproxy/gateway/pull/4287?dropdown=coverage&src=pr&el=continue&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=envoyproxy).   
:loudspeaker: Have feedback on the report? [Share it here](https://about.codecov.io/codecov-pr-comment-feedback/?utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=envoyproxy).

shawnh2: /retest
shawnh2: Wait for the benchmark report.
qicz: IMO,  not only routes but also secrets and configmaps. 
qicz: /retest
arkodg: seeing this error
```
2024-09-20T04:21:25.7708266Z ##[error]internal/cmd/options/global.go:10:2: k8s.io/cli-runtime@v0.31.1: Get "https://proxy.golang.org/k8s.io/cli-runtime/@v/v0.31.1.zip": stream error: stream ID 1; PROTOCOL_ERROR
```
Xunzhuo: /retest
shawnh2: seems 1000 httproutes will cause oom
zirain: give one more try after https://github.com/envoyproxy/gateway/pull/4454 merged.

Patch:
diff --git a/api/v1alpha1/httproutefilter_types.go b/api/v1alpha1/httproutefilter_types.go
index 9ae8be598..3259fabc8 100644
--- a/api/v1alpha1/httproutefilter_types.go
+++ b/api/v1alpha1/httproutefilter_types.go
@@ -43,7 +43,6 @@ type HTTPURLRewriteFilter struct {
 	// forwarding.
 	//
 	// +optional
-	// +notImplementedHide
 	Hostname *HTTPHostnameModifier `json:"hostname,omitempty"`
 	// Path defines a path rewrite.
 	//
@@ -83,12 +82,12 @@ const (
 type HTTPHostnameModifierType string
 
 const (
-	// HeaderHTTPHostnameModifier indicates that the Host header value would be replaced with the value of the header specified in setFromHeader.
+	// HeaderHTTPHostnameModifier indicates that the Host header value would be replaced with the value of the header specified in header.
 	// https://www.envoyproxy.io/docs/envoy/latest/api-v3/config/route/v3/route_components.proto#envoy-v3-api-field-config-route-v3-routeaction-host-rewrite-header
-	HeaderHTTPHostnameModifier HTTPHostnameModifierType = "SetFromHeader"
+	HeaderHTTPHostnameModifier HTTPHostnameModifierType = "Header"
 	// BackendHTTPHostnameModifier indicates that the Host header value would be replaced by the DNS name of the backend if it exists.
 	// https://www.envoyproxy.io/docs/envoy/latest/api-v3/config/route/v3/route_components.proto#envoy-v3-api-field-config-route-v3-routeaction-auto-host-rewrite
-	BackendHTTPHostnameModifier HTTPHostnameModifierType = "SetFromBackend"
+	BackendHTTPHostnameModifier HTTPHostnameModifierType = "Backend"
 )
 
 type ReplaceRegexMatch struct {
@@ -129,16 +128,16 @@ type HTTPPathModifier struct {
 	ReplaceRegexMatch *ReplaceRegexMatch `json:"replaceRegexMatch,omitempty"`
 }
 
-// +kubebuilder:validation:XValidation:message="setFromHeader must be nil if the type is not SetFromHeader",rule="!(has(self.setFromHeader) && self.type != 'SetFromHeader')"
-// +kubebuilder:validation:XValidation:message="setFromHeader must be specified for SetFromHeader type",rule="!(!has(self.setFromHeader) && self.type == 'SetFromHeader')"
+// +kubebuilder:validation:XValidation:message="header must be nil if the type is not Header",rule="!(has(self.header) && self.type != 'Header')"
+// +kubebuilder:validation:XValidation:message="header must be specified for Header type",rule="!(!has(self.header) && self.type == 'Header')"
 type HTTPHostnameModifier struct {
-	// +kubebuilder:validation:Enum=SetFromHeader;SetFromBackend
+	// +kubebuilder:validation:Enum=Header;Backend
 	// +kubebuilder:validation:Required
 	Type HTTPHostnameModifierType `json:"type"`
 
-	// SetFromHeader is the name of the header whose value would be used to rewrite the Host header
+	// Header is the name of the header whose value would be used to rewrite the Host header
 	// +optional
-	SetFromHeader *string `json:"setFromHeader,omitempty"`
+	Header *string `json:"header,omitempty"`
 }
 
 //+kubebuilder:object:root=true
diff --git a/api/v1alpha1/zz_generated.deepcopy.go b/api/v1alpha1/zz_generated.deepcopy.go
index c225d65d3..f2cf9072f 100644
--- a/api/v1alpha1/zz_generated.deepcopy.go
+++ b/api/v1alpha1/zz_generated.deepcopy.go
@@ -2747,8 +2747,8 @@ func (in *HTTPExtAuthService) DeepCopy() *HTTPExtAuthService {
 // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
 func (in *HTTPHostnameModifier) DeepCopyInto(out *HTTPHostnameModifier) {
 	*out = *in
-	if in.SetFromHeader != nil {
-		in, out := &in.SetFromHeader, &out.SetFromHeader
+	if in.Header != nil {
+		in, out := &in.Header, &out.Header
 		*out = new(string)
 		**out = **in
 	}
diff --git a/charts/gateway-helm/crds/generated/gateway.envoyproxy.io_httproutefilters.yaml b/charts/gateway-helm/crds/generated/gateway.envoyproxy.io_httproutefilters.yaml
index 672cfb59d..195bf24ec 100644
--- a/charts/gateway-helm/crds/generated/gateway.envoyproxy.io_httproutefilters.yaml
+++ b/charts/gateway-helm/crds/generated/gateway.envoyproxy.io_httproutefilters.yaml
@@ -137,25 +137,25 @@ spec:
                       Hostname is the value to be used to replace the Host header value during
                       forwarding.
                     properties:
-                      setFromHeader:
-                        description: SetFromHeader is the name of the header whose
-                          value would be used to rewrite the Host header
+                      header:
+                        description: Header is the name of the header whose value
+                          would be used to rewrite the Host header
                         type: string
                       type:
                         description: HTTPPathModifierType defines the type of Hostname
                           rewrite.
                         enum:
-                        - SetFromHeader
-                        - SetFromBackend
+                        - Header
+                        - Backend
                         type: string
                     required:
                     - type
                     type: object
                     x-kubernetes-validations:
-                    - message: setFromHeader must be nil if the type is not SetFromHeader
-                      rule: '!(has(self.setFromHeader) && self.type != ''SetFromHeader'')'
-                    - message: setFromHeader must be specified for SetFromHeader type
-                      rule: '!(!has(self.setFromHeader) && self.type == ''SetFromHeader'')'
+                    - message: header must be nil if the type is not Header
+                      rule: '!(has(self.header) && self.type != ''Header'')'
+                    - message: header must be specified for Header type
+                      rule: '!(!has(self.header) && self.type == ''Header'')'
                   path:
                     description: Path defines a path rewrite.
                     properties:
diff --git a/internal/gatewayapi/filters.go b/internal/gatewayapi/filters.go
index 41acc4c76..e969b7365 100644
--- a/internal/gatewayapi/filters.go
+++ b/internal/gatewayapi/filters.go
@@ -11,6 +11,7 @@ import (
 	"strings"
 
 	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
+	"k8s.io/utils/ptr"
 	gwapiv1 "sigs.k8s.io/gateway-api/apis/v1"
 
 	egv1a1 "github.com/envoyproxy/gateway/api/v1alpha1"
@@ -147,14 +148,46 @@ func (t *Translator) ProcessGRPCFilters(parentRef *RouteParentContext,
 	return httpFiltersContext
 }
 
+// Checks if the context and the rewrite both contain a core gw-api HTTP URL rewrite
+func hasMultipleCoreRewrites(rewrite *gwapiv1.HTTPURLRewriteFilter, contextRewrite *ir.URLRewrite) bool {
+	contextHasCoreRewrites := contextRewrite.Path != nil && (contextRewrite.Path.FullReplace != nil ||
+		contextRewrite.Path.PrefixMatchReplace != nil) || (contextRewrite.Host != nil && contextRewrite.Host.Name != nil)
+	rewriteHasCoreRewrites := rewrite.Hostname != nil || rewrite.Path != nil
+	return contextHasCoreRewrites && rewriteHasCoreRewrites
+}
+
+// Checks if the context and the rewrite both contain a envoy-gateway extended HTTP URL rewrite
+func hasMultipleExtensionRewrites(rewrite *egv1a1.HTTPURLRewriteFilter, contextRewrite *ir.URLRewrite) bool {
+	contextHasExtensionRewrites := (contextRewrite.Path != nil && contextRewrite.Path.RegexMatchReplace != nil) ||
+		(contextRewrite.Host != nil && (contextRewrite.Host.Header != nil || contextRewrite.Host.Backend != nil))
+
+	return contextHasExtensionRewrites && (rewrite.Hostname != nil || rewrite.Path != nil)
+}
+
+// Checks if the context and the gw-api core rewrite both contain an HTTP URL rewrite that creates a conflict (e.g. both rewrite path)
+func hasConflictingCoreAndExtensionRewrites(rewrite *gwapiv1.HTTPURLRewriteFilter, contextRewrite *ir.URLRewrite) bool {
+	contextHasExtensionPathRewrites := contextRewrite.Path != nil && contextRewrite.Path.RegexMatchReplace != nil
+	contextHasExtensionHostRewrites := contextRewrite.Host != nil && (contextRewrite.Host.Header != nil ||
+		contextRewrite.Host.Backend != nil)
+	return (rewrite.Hostname != nil && contextHasExtensionHostRewrites) || (rewrite.Path != nil && contextHasExtensionPathRewrites)
+}
+
+// Checks if the context and the envoy-gateway extended rewrite both contain an HTTP URL rewrite that creates a conflict (e.g. both rewrite path)
+func hasConflictingExtensionAndCoreRewrites(rewrite *egv1a1.HTTPURLRewriteFilter, contextRewrite *ir.URLRewrite) bool {
+	contextHasCorePathRewrites := contextRewrite.Path != nil && (contextRewrite.Path.FullReplace != nil ||
+		contextRewrite.Path.PrefixMatchReplace != nil)
+	contextHasCoreHostnameRewrites := contextRewrite.Host != nil && contextRewrite.Host.Name != nil
+
+	return (rewrite.Hostname != nil && contextHasCoreHostnameRewrites) || (rewrite.Path != nil && contextHasCorePathRewrites)
+}
+
 func (t *Translator) processURLRewriteFilter(
 	rewrite *gwapiv1.HTTPURLRewriteFilter,
 	filterContext *HTTPFiltersContext,
 ) {
 	if filterContext.URLRewrite != nil {
-		if filterContext.URLRewrite.Hostname != nil ||
-			filterContext.URLRewrite.Path.FullReplace != nil ||
-			filterContext.URLRewrite.Path.PrefixMatchReplace != nil {
+		if hasMultipleCoreRewrites(rewrite, filterContext.URLRewrite) ||
+			hasConflictingCoreAndExtensionRewrites(rewrite, filterContext.URLRewrite) {
 			routeStatus := GetRouteStatus(filterContext.Route)
 			status.SetRouteStatusCondition(routeStatus,
 				filterContext.ParentRef.routeParentStatusIdx,
@@ -188,7 +221,9 @@ func (t *Translator) processURLRewriteFilter(
 			return
 		}
 		redirectHost := string(*rewrite.Hostname)
-		newURLRewrite.Hostname = &redirectHost
+		newURLRewrite.Host = &ir.HTTPHostModifier{
+			Name: &redirectHost,
+		}
 	}
 
 	if rewrite.Path != nil {
@@ -751,48 +786,12 @@ func (t *Translator) processExtensionRefHTTPFilter(extFilter *gwapiv1.LocalObjec
 
 	if string(extFilter.Kind) == egv1a1.KindHTTPRouteFilter {
 		for _, hrf := range resources.HTTPRouteFilters {
-			if hrf.Namespace == filterNs && hrf.Name == string(extFilter.Name) &&
-				hrf.Spec.URLRewrite.Path.Type == egv1a1.RegexHTTPPathModifier {
-
-				if hrf.Spec.URLRewrite.Path.ReplaceRegexMatch == nil ||
-					hrf.Spec.URLRewrite.Path.ReplaceRegexMatch.Pattern == "" {
-					errMsg := "ReplaceRegexMatch Pattern must be set when rewrite path type is \"ReplaceRegexMatch\""
-					routeStatus := GetRouteStatus(filterContext.Route)
-					status.SetRouteStatusCondition(routeStatus,
-						filterContext.ParentRef.routeParentStatusIdx,
-						filterContext.Route.GetGeneration(),
-						gwapiv1.RouteConditionAccepted,
-						metav1.ConditionFalse,
-						gwapiv1.RouteReasonUnsupportedValue,
-						errMsg,
-					)
-					return
-				} else if _, err := regexp.Compile(hrf.Spec.URLRewrite.Path.ReplaceRegexMatch.Pattern); err != nil {
-					// Avoid envoy NACKs due to invalid regex.
-					// Golang's regexp is almost identical to RE2: https://pkg.go.dev/regexp/syntax
-					errMsg := "ReplaceRegexMatch must be a valid RE2 regular expression"
-					routeStatus := GetRouteStatus(filterContext.Route)
-					status.SetRouteStatusCondition(routeStatus,
-						filterContext.ParentRef.routeParentStatusIdx,
-						filterContext.Route.GetGeneration(),
-						gwapiv1.RouteConditionAccepted,
-						metav1.ConditionFalse,
-						gwapiv1.RouteReasonUnsupportedValue,
-						errMsg,
-					)
-					return
-				}
-
-				rmr := &ir.RegexMatchReplace{
-					Pattern:      hrf.Spec.URLRewrite.Path.ReplaceRegexMatch.Pattern,
-					Substitution: hrf.Spec.URLRewrite.Path.ReplaceRegexMatch.Substitution,
-				}
+			if hrf.Namespace == filterNs && hrf.Name == string(extFilter.Name) {
+				if hrf.Spec.URLRewrite != nil {
 
-				if filterContext.HTTPFilterIR.URLRewrite != nil {
-					// If path IR is already set - check for a conflict
-					if filterContext.HTTPFilterIR.URLRewrite.Path != nil {
-						path := filterContext.HTTPFilterIR.URLRewrite.Path
-						if path.RegexMatchReplace != nil || path.PrefixMatchReplace != nil || path.FullReplace != nil {
+					if filterContext.URLRewrite != nil {
+						if hasMultipleExtensionRewrites(hrf.Spec.URLRewrite, filterContext.URLRewrite) ||
+							hasConflictingExtensionAndCoreRewrites(hrf.Spec.URLRewrite, filterContext.URLRewrite) {
 							routeStatus := GetRouteStatus(filterContext.Route)
 							status.SetRouteStatusCondition(routeStatus,
 								filterContext.ParentRef.routeParentStatusIdx,
@@ -804,19 +803,100 @@ func (t *Translator) processExtensionRefHTTPFilter(extFilter *gwapiv1.LocalObjec
 							)
 							return
 						}
-					} else { // no path
-						filterContext.HTTPFilterIR.URLRewrite.Path = &ir.ExtendedHTTPPathModifier{
-							RegexMatchReplace: rmr,
+					}
+
+					if hrf.Spec.URLRewrite.Path != nil {
+						if hrf.Spec.URLRewrite.Path.Type == egv1a1.RegexHTTPPathModifier {
+							if hrf.Spec.URLRewrite.Path.ReplaceRegexMatch == nil ||
+								hrf.Spec.URLRewrite.Path.ReplaceRegexMatch.Pattern == "" {
+								errMsg := "ReplaceRegexMatch Pattern must be set when rewrite path type is \"ReplaceRegexMatch\""
+								routeStatus := GetRouteStatus(filterContext.Route)
+								status.SetRouteStatusCondition(routeStatus,
+									filterContext.ParentRef.routeParentStatusIdx,
+									filterContext.Route.GetGeneration(),
+									gwapiv1.RouteConditionAccepted,
+									metav1.ConditionFalse,
+									gwapiv1.RouteReasonUnsupportedValue,
+									errMsg,
+								)
+								return
+							} else if _, err := regexp.Compile(hrf.Spec.URLRewrite.Path.ReplaceRegexMatch.Pattern); err != nil {
+								// Avoid envoy NACKs due to invalid regex.
+								// Golang's regexp is almost identical to RE2: https://pkg.go.dev/regexp/syntax
+								errMsg := "ReplaceRegexMatch must be a valid RE2 regular expression"
+								routeStatus := GetRouteStatus(filterContext.Route)
+								status.SetRouteStatusCondition(routeStatus,
+									filterContext.ParentRef.routeParentStatusIdx,
+									filterContext.Route.GetGeneration(),
+									gwapiv1.RouteConditionAccepted,
+									metav1.ConditionFalse,
+									gwapiv1.RouteReasonUnsupportedValue,
+									errMsg,
+								)
+								return
+							}
+
+							rmr := &ir.RegexMatchReplace{
+								Pattern:      hrf.Spec.URLRewrite.Path.ReplaceRegexMatch.Pattern,
+								Substitution: hrf.Spec.URLRewrite.Path.ReplaceRegexMatch.Substitution,
+							}
+
+							if filterContext.HTTPFilterIR.URLRewrite != nil {
+								if filterContext.HTTPFilterIR.URLRewrite.Path == nil {
+									filterContext.HTTPFilterIR.URLRewrite.Path = &ir.ExtendedHTTPPathModifier{
+										RegexMatchReplace: rmr,
+									}
+									return
+								}
+							} else { // no url rewrite
+								filterContext.HTTPFilterIR.URLRewrite = &ir.URLRewrite{
+									Path: &ir.ExtendedHTTPPathModifier{
+										RegexMatchReplace: rmr,
+									},
+								}
+								return
+							}
 						}
-						return
 					}
-				} else { // no url rewrite
-					filterContext.HTTPFilterIR.URLRewrite = &ir.URLRewrite{
-						Path: &ir.ExtendedHTTPPathModifier{
-							RegexMatchReplace: rmr,
-						},
+
+					if hrf.Spec.URLRewrite.Hostname != nil {
+						var hm *ir.HTTPHostModifier
+						if hrf.Spec.URLRewrite.Hostname.Type == egv1a1.HeaderHTTPHostnameModifier {
+							if hrf.Spec.URLRewrite.Hostname.Header == nil {
+								errMsg := "Header must be set when rewrite path type is \"Header\""
+								routeStatus := GetRouteStatus(filterContext.Route)
+								status.SetRouteStatusCondition(routeStatus,
+									filterContext.ParentRef.routeParentStatusIdx,
+									filterContext.Route.GetGeneration(),
+									gwapiv1.RouteConditionAccepted,
+									metav1.ConditionFalse,
+									gwapiv1.RouteReasonUnsupportedValue,
+									errMsg,
+								)
+								return
+							}
+							hm = &ir.HTTPHostModifier{
+								Header: hrf.Spec.URLRewrite.Hostname.Header,
+							}
+						} else if hrf.Spec.URLRewrite.Hostname.Type == egv1a1.BackendHTTPHostnameModifier {
+							hm = &ir.HTTPHostModifier{
+								Backend: ptr.To(true),
+							}
+						}
+
+						if filterContext.HTTPFilterIR.URLRewrite != nil {
+							if filterContext.HTTPFilterIR.URLRewrite.Host == nil {
+								filterContext.HTTPFilterIR.URLRewrite.Host = hm
+								return
+							}
+						} else { // no url rewrite
+							filterContext.HTTPFilterIR.URLRewrite = &ir.URLRewrite{
+								Host: hm,
+							}
+							return
+						}
 					}
-					return
+
 				}
 			}
 		}
diff --git a/internal/ir/xds.go b/internal/ir/xds.go
index cb5021f4c..00edaf21b 100644
--- a/internal/ir/xds.go
+++ b/internal/ir/xds.go
@@ -55,6 +55,7 @@ var (
 	ErrHTTPPathModifierDoubleReplace           = errors.New("redirect filter cannot have a path modifier that supplies more than one of fullPathReplace, prefixMatchReplace and regexMatchReplace")
 	ErrHTTPPathModifierNoReplace               = errors.New("redirect filter cannot have a path modifier that does not supply either fullPathReplace, prefixMatchReplace or regexMatchReplace")
 	ErrHTTPPathRegexModifierNoSetting          = errors.New("redirect filter cannot have a path modifier that does not supply either fullPathReplace, prefixMatchReplace or regexMatchReplace")
+	ErrHTTPHostModifierDoubleReplace           = errors.New("redirect filter cannot have a host modifier that supplies more than one of Hostname, Header and Backend")
 	ErrAddHeaderEmptyName                      = errors.New("header modifier filter cannot configure a header without a name to be added")
 	ErrAddHeaderDuplicate                      = errors.New("header modifier filter attempts to add the same header more than once (case insensitive)")
 	ErrRemoveHeaderDuplicate                   = errors.New("header modifier filter attempts to remove the same header more than once (case insensitive)")
@@ -1382,8 +1383,8 @@ func (r DirectResponse) Validate() error {
 type URLRewrite struct {
 	// Path contains config for rewriting the path of the request.
 	Path *ExtendedHTTPPathModifier `json:"path,omitempty" yaml:"path,omitempty"`
-	// Hostname configures the replacement of the request's hostname.
-	Hostname *string `json:"hostname,omitempty" yaml:"hostname,omitempty"`
+	// Host configures the replacement of the request's host header.
+	Host *HTTPHostModifier `json:"host,omitempty" yaml:"host,omitempty"`
 }
 
 // Validate the fields within the URLRewrite structure
@@ -1396,6 +1397,12 @@ func (r URLRewrite) Validate() error {
 		}
 	}
 
+	if r.Host != nil {
+		if err := r.Host.Validate(); err != nil {
+			errs = errors.Join(errs, err)
+		}
+	}
+
 	return errs
 }
 
@@ -1499,6 +1506,34 @@ func (r ExtendedHTTPPathModifier) Validate() error {
 	return errs
 }
 
+// HTTPHostModifier holds instructions for how to modify the host of a request
+// with both core gateway-api and extended envoy gateway capabilities
+// +k8s:deepcopy-gen=true
+type HTTPHostModifier struct {
+	Name    *string `json:"name,omitempty" yaml:"name,omitempty"`
+	Header  *string `json:"header,omitempty" yaml:"header,omitempty"`
+	Backend *bool   `json:"backend,omitempty" yaml:"backend,omitempty"`
+}
+
+// Validate the fields within the HTTPPathModifier structure
+func (r HTTPHostModifier) Validate() error {
+	var errs error
+
+	rewrites := []bool{r.Name != nil, r.Header != nil, r.Backend != nil}
+	rwc := 0
+	for _, rw := range rewrites {
+		if rw {
+			rwc++
+		}
+	}
+
+	if rwc > 1 {
+		errs = errors.Join(errs, ErrHTTPHostModifierDoubleReplace)
+	}
+
+	return errs
+}
+
 // StringMatch holds the various match conditions.
 // Only one of Exact, Prefix, SafeRegex or Distinct can be set.
 // +k8s:deepcopy-gen=true
diff --git a/internal/ir/zz_generated.deepcopy.go b/internal/ir/zz_generated.deepcopy.go
index 791b6d5dd..111f26613 100644
--- a/internal/ir/zz_generated.deepcopy.go
+++ b/internal/ir/zz_generated.deepcopy.go
@@ -1270,6 +1270,36 @@ func (in *HTTPHealthChecker) DeepCopy() *HTTPHealthChecker {
 	return out
 }
 
+// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
+func (in *HTTPHostModifier) DeepCopyInto(out *HTTPHostModifier) {
+	*out = *in
+	if in.Name != nil {
+		in, out := &in.Name, &out.Name
+		*out = new(string)
+		**out = **in
+	}
+	if in.Header != nil {
+		in, out := &in.Header, &out.Header
+		*out = new(string)
+		**out = **in
+	}
+	if in.Backend != nil {
+		in, out := &in.Backend, &out.Backend
+		*out = new(bool)
+		**out = **in
+	}
+}
+
+// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new HTTPHostModifier.
+func (in *HTTPHostModifier) DeepCopy() *HTTPHostModifier {
+	if in == nil {
+		return nil
+	}
+	out := new(HTTPHostModifier)
+	in.DeepCopyInto(out)
+	return out
+}
+
 // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
 func (in *HTTPListener) DeepCopyInto(out *HTTPListener) {
 	*out = *in
@@ -3341,10 +3371,10 @@ func (in *URLRewrite) DeepCopyInto(out *URLRewrite) {
 		*out = new(ExtendedHTTPPathModifier)
 		(*in).DeepCopyInto(*out)
 	}
-	if in.Hostname != nil {
-		in, out := &in.Hostname, &out.Hostname
-		*out = new(string)
-		**out = **in
+	if in.Host != nil {
+		in, out := &in.Host, &out.Host
+		*out = new(HTTPHostModifier)
+		(*in).DeepCopyInto(*out)
 	}
 }
 
diff --git a/internal/xds/translator/route.go b/internal/xds/translator/route.go
index a8ec4a291..e1d790268 100644
--- a/internal/xds/translator/route.go
+++ b/internal/xds/translator/route.go
@@ -417,9 +417,21 @@ func buildXdsURLRewriteAction(destName string, urlRewrite *ir.URLRewrite, pathMa
 		}
 	}
 
-	if urlRewrite.Hostname != nil {
-		routeAction.HostRewriteSpecifier = &routev3.RouteAction_HostRewriteLiteral{
-			HostRewriteLiteral: *urlRewrite.Hostname,
+	if urlRewrite.Host != nil {
+
+		switch {
+		case urlRewrite.Host.Name != nil:
+			routeAction.HostRewriteSpecifier = &routev3.RouteAction_HostRewriteLiteral{
+				HostRewriteLiteral: *urlRewrite.Host.Name,
+			}
+		case urlRewrite.Host.Header != nil:
+			routeAction.HostRewriteSpecifier = &routev3.RouteAction_HostRewriteHeader{
+				HostRewriteHeader: *urlRewrite.Host.Header,
+			}
+		case urlRewrite.Host.Backend != nil:
+			routeAction.HostRewriteSpecifier = &routev3.RouteAction_AutoHostRewrite{
+				AutoHostRewrite: wrapperspb.Bool(true),
+			}
 		}
 
 		routeAction.AppendXForwardedHost = true


Test patch:
diff --git a/internal/gatewayapi/testdata/httproute-with-urlrewrite-filter-hostname-prefix-replace.out.yaml b/internal/gatewayapi/testdata/httproute-with-urlrewrite-filter-hostname-prefix-replace.out.yaml
index 1577ab27e..8e3079c9b 100644
--- a/internal/gatewayapi/testdata/httproute-with-urlrewrite-filter-hostname-prefix-replace.out.yaml
+++ b/internal/gatewayapi/testdata/httproute-with-urlrewrite-filter-hostname-prefix-replace.out.yaml
@@ -144,7 +144,8 @@ xdsIR:
           name: ""
           prefix: /
         urlRewrite:
-          hostname: rewrite.com
+          host:
+            name: rewrite.com
           path:
             fullReplace: null
             prefixMatchReplace: /rewrite
diff --git a/internal/gatewayapi/testdata/httproute-with-urlrewrite-filter-hostname.out.yaml b/internal/gatewayapi/testdata/httproute-with-urlrewrite-filter-hostname.out.yaml
index 658725825..c0d8cce8b 100644
--- a/internal/gatewayapi/testdata/httproute-with-urlrewrite-filter-hostname.out.yaml
+++ b/internal/gatewayapi/testdata/httproute-with-urlrewrite-filter-hostname.out.yaml
@@ -141,4 +141,5 @@ xdsIR:
           name: ""
           prefix: /
         urlRewrite:
-          hostname: rewrite.com
+          host:
+            name: rewrite.com
diff --git a/internal/gatewayapi/testdata/httproute-with-urlrewrite-filter-invalid-filter-type.out.yaml b/internal/gatewayapi/testdata/httproute-with-urlrewrite-filter-invalid-filter-type.out.yaml
index d0d62e98a..7cbff74f2 100644
--- a/internal/gatewayapi/testdata/httproute-with-urlrewrite-filter-invalid-filter-type.out.yaml
+++ b/internal/gatewayapi/testdata/httproute-with-urlrewrite-filter-invalid-filter-type.out.yaml
@@ -141,4 +141,5 @@ xdsIR:
           name: ""
           prefix: /
         urlRewrite:
-          hostname: urlrewrite.envoyproxy.io
+          host:
+            name: urlrewrite.envoyproxy.io
diff --git a/internal/gatewayapi/testdata/httproute-with-urlrewrite-filter-regex-match-replace-http.out.yaml b/internal/gatewayapi/testdata/httproute-with-urlrewrite-filter-regex-match-replace-http.out.yaml
index 5c8d2527a..c42f39345 100644
--- a/internal/gatewayapi/testdata/httproute-with-urlrewrite-filter-regex-match-replace-http.out.yaml
+++ b/internal/gatewayapi/testdata/httproute-with-urlrewrite-filter-regex-match-replace-http.out.yaml
@@ -308,7 +308,8 @@ xdsIR:
           name: ""
           prefix: /host-and-regex-path
         urlRewrite:
-          hostname: rewrite.com
+          host:
+            name: rewrite.com
           path:
             fullReplace: null
             prefixMatchReplace: null
@@ -336,7 +337,8 @@ xdsIR:
           name: ""
           prefix: /regex-path-and-host
         urlRewrite:
-          hostname: rewrite.com
+          host:
+            name: rewrite.com
       - destination:
           name: httproute/default/httproute-1/rule/0
           settings:
diff --git a/internal/gatewayapi/testdata/httproute-with-urlrewrite-filter-regex-match-replace-invalid.out.yaml b/internal/gatewayapi/testdata/httproute-with-urlrewrite-filter-regex-match-replace-invalid.out.yaml
index fb9e85a63..17ffc680f 100644
--- a/internal/gatewayapi/testdata/httproute-with-urlrewrite-filter-regex-match-replace-invalid.out.yaml
+++ b/internal/gatewayapi/testdata/httproute-with-urlrewrite-filter-regex-match-replace-invalid.out.yaml
@@ -164,9 +164,9 @@ httpRoutes:
     parents:
     - conditions:
       - lastTransitionTime: null
-        message: Route is accepted
-        reason: Accepted
-        status: "True"
+        message: Cannot configure multiple urlRewrite filters for a single HTTPRouteRule
+        reason: UnsupportedValue
+        status: "False"
         type: Accepted
       - lastTransitionTime: null
         message: Resolved all the Object references for the Route
@@ -356,28 +356,3 @@ xdsIR:
         escapedSlashesAction: UnescapeAndRedirect
         mergeSlashes: true
       port: 10080
-      routes:
-      - destination:
-          name: httproute/default/httproute-multiple-path-rewrites-1/rule/0
-          settings:
-          - addressType: IP
-            endpoints:
-            - host: 7.7.7.7
-              port: 8080
-            protocol: HTTP
-            weight: 1
-        hostname: gateway.envoyproxy.io
-        isHTTP2: false
-        metadata:
-          kind: HTTPRoute
-          name: httproute-multiple-path-rewrites-1
-          namespace: default
-        name: httproute/default/httproute-multiple-path-rewrites-1/rule/0/match/0/gateway_envoyproxy_io
-        pathMatch:
-          distinct: false
-          name: ""
-          prefix: /ext-first
-        urlRewrite:
-          path:
-            fullReplace: null
-            prefixMatchReplace: /rewrite
diff --git a/internal/gatewayapi/testdata/httproute-with-urlrewrite-hostname-filter-invalid.in.yaml b/internal/gatewayapi/testdata/httproute-with-urlrewrite-hostname-filter-invalid.in.yaml
new file mode 100644
index 000000000..5a7f44990
--- /dev/null
+++ b/internal/gatewayapi/testdata/httproute-with-urlrewrite-hostname-filter-invalid.in.yaml
@@ -0,0 +1,236 @@
+gateways:
+  - apiVersion: gateway.networking.k8s.io/v1
+    kind: Gateway
+    metadata:
+      namespace: envoy-gateway
+      name: gateway-1
+    spec:
+      gatewayClassName: envoy-gateway-class
+      listeners:
+        - name: http
+          protocol: HTTP
+          port: 80
+          hostname: "*.envoyproxy.io"
+          allowedRoutes:
+            namespaces:
+              from: All
+httpRoutes:
+  - apiVersion: gateway.networking.k8s.io/v1
+    kind: HTTPRoute
+    metadata:
+      namespace: default
+      name: httproute-invalid-header
+    spec:
+      hostnames:
+        - gateway.envoyproxy.io
+      parentRefs:
+        - namespace: envoy-gateway
+          name: gateway-1
+          sectionName: http
+      rules:
+        - matches:
+            - path:
+                value: "/invalid-header"
+          backendRefs:
+            - name: service-1
+              port: 8080
+          filters:
+            - type: ExtensionRef
+              extensionRef:
+                group: gateway.envoyproxy.io
+                kind: HTTPRouteFilter
+                name: invalid-header
+  - apiVersion: gateway.networking.k8s.io/v1
+    kind: HTTPRoute
+    metadata:
+      namespace: default
+      name: httproute-multiple-host-rewrites-1
+    spec:
+      hostnames:
+        - gateway.envoyproxy.io
+      parentRefs:
+        - namespace: envoy-gateway
+          name: gateway-1
+          sectionName: http
+      rules:
+        - matches:
+            - path:
+                value: "/ext-first"
+          backendRefs:
+            - name: service-1
+              port: 8080
+          filters:
+            - type: ExtensionRef
+              extensionRef:
+                group: gateway.envoyproxy.io
+                kind: HTTPRouteFilter
+                name: valid-header
+            - type: URLRewrite
+              urlRewrite:
+                hostname: "rewrite.com"
+  - apiVersion: gateway.networking.k8s.io/v1
+    kind: HTTPRoute
+    metadata:
+      namespace: default
+      name: httproute-multiple-path-rewrites-2
+    spec:
+      hostnames:
+        - gateway.envoyproxy.io
+      parentRefs:
+        - namespace: envoy-gateway
+          name: gateway-1
+          sectionName: http
+      rules:
+        - matches:
+            - path:
+                value: "/inline-first"
+          backendRefs:
+            - name: service-1
+              port: 8080
+          filters:
+            - type: URLRewrite
+              urlRewrite:
+                hostname: "rewrite.com"
+            - type: ExtensionRef
+              extensionRef:
+                group: gateway.envoyproxy.io
+                kind: HTTPRouteFilter
+                name: valid-header
+  - apiVersion: gateway.networking.k8s.io/v1
+    kind: HTTPRoute
+    metadata:
+      namespace: default
+      name: httproute-multiple-header-host-rewrites
+    spec:
+      hostnames:
+        - gateway.envoyproxy.io
+      parentRefs:
+        - namespace: envoy-gateway
+          name: gateway-1
+          sectionName: http
+      rules:
+        - matches:
+            - path:
+                value: "/two-headers"
+          backendRefs:
+            - name: service-1
+              port: 8080
+          filters:
+            - type: ExtensionRef
+              extensionRef:
+                group: gateway.envoyproxy.io
+                kind: HTTPRouteFilter
+                name: valid-header
+            - type: ExtensionRef
+              extensionRef:
+                group: gateway.envoyproxy.io
+                kind: HTTPRouteFilter
+                name: valid-header-2
+  - apiVersion: gateway.networking.k8s.io/v1
+    kind: HTTPRoute
+    metadata:
+      namespace: default
+      name: httproute-multiple-header-host-rewrites
+    spec:
+      hostnames:
+        - gateway.envoyproxy.io
+      parentRefs:
+        - namespace: envoy-gateway
+          name: gateway-1
+          sectionName: http
+      rules:
+        - matches:
+            - path:
+                value: "/two-backends"
+          backendRefs:
+            - name: service-1
+              port: 8080
+          filters:
+            - type: ExtensionRef
+              extensionRef:
+                group: gateway.envoyproxy.io
+                kind: HTTPRouteFilter
+                name: valid-backend
+            - type: ExtensionRef
+              extensionRef:
+                group: gateway.envoyproxy.io
+                kind: HTTPRouteFilter
+                name: valid-backend-2
+  - apiVersion: gateway.networking.k8s.io/v1
+    kind: HTTPRoute
+    metadata:
+      namespace: default
+      name: httproute-header-and-backend-host-rewrites
+    spec:
+      hostnames:
+        - gateway.envoyproxy.io
+      parentRefs:
+        - namespace: envoy-gateway
+          name: gateway-1
+          sectionName: http
+      rules:
+        - matches:
+            - path:
+                value: "/header-and-backend"
+          backendRefs:
+            - name: service-1
+              port: 8080
+          filters:
+            - type: ExtensionRef
+              extensionRef:
+                group: gateway.envoyproxy.io
+                kind: HTTPRouteFilter
+                name: valid-header
+            - type: ExtensionRef
+              extensionRef:
+                group: gateway.envoyproxy.io
+                kind: HTTPRouteFilter
+                name: valid-header
+httpFilters:
+  - apiVersion: gateway.envoyproxy.io/v1alpha1
+    kind: HTTPRouteFilter
+    metadata:
+      name: valid-header
+      namespace: default
+    spec:
+      urlRewrite:
+        hostname:
+          type: Header
+          header: my-host
+  - apiVersion: gateway.envoyproxy.io/v1alpha1
+    kind: HTTPRouteFilter
+    metadata:
+      name: valid-header-2
+      namespace: default
+    spec:
+      urlRewrite:
+        hostname:
+          type: Header
+          header: my-host2
+  - apiVersion: gateway.envoyproxy.io/v1alpha1
+    kind: HTTPRouteFilter
+    metadata:
+      name: valid-backend
+      namespace: default
+    spec:
+      urlRewrite:
+        hostname:
+          type: Backend
+  - apiVersion: gateway.envoyproxy.io/v1alpha1
+    kind: HTTPRouteFilter
+    metadata:
+      name: valid-backend-2
+      namespace: default
+    spec:
+      urlRewrite:
+        hostname:
+          type: Backend
+  - apiVersion: gateway.envoyproxy.io/v1alpha1
+    kind: HTTPRouteFilter
+    metadata:
+      name: invalid-header
+      namespace: default
+    spec:
+      urlRewrite:
+        hostname:
+          type: Header
diff --git a/internal/gatewayapi/testdata/httproute-with-urlrewrite-hostname-filter-invalid.out.yaml b/internal/gatewayapi/testdata/httproute-with-urlrewrite-hostname-filter-invalid.out.yaml
new file mode 100644
index 000000000..ab24ec0e8
--- /dev/null
+++ b/internal/gatewayapi/testdata/httproute-with-urlrewrite-hostname-filter-invalid.out.yaml
@@ -0,0 +1,364 @@
+gateways:
+- apiVersion: gateway.networking.k8s.io/v1
+  kind: Gateway
+  metadata:
+    creationTimestamp: null
+    name: gateway-1
+    namespace: envoy-gateway
+  spec:
+    gatewayClassName: envoy-gateway-class
+    listeners:
+    - allowedRoutes:
+        namespaces:
+          from: All
+      hostname: '*.envoyproxy.io'
+      name: http
+      port: 80
+      protocol: HTTP
+  status:
+    listeners:
+    - attachedRoutes: 6
+      conditions:
+      - lastTransitionTime: null
+        message: Sending translated listener configuration to the data plane
+        reason: Programmed
+        status: "True"
+        type: Programmed
+      - lastTransitionTime: null
+        message: Listener has been successfully translated
+        reason: Accepted
+        status: "True"
+        type: Accepted
+      - lastTransitionTime: null
+        message: Listener references have been resolved
+        reason: ResolvedRefs
+        status: "True"
+        type: ResolvedRefs
+      name: http
+      supportedKinds:
+      - group: gateway.networking.k8s.io
+        kind: HTTPRoute
+      - group: gateway.networking.k8s.io
+        kind: GRPCRoute
+httpRoutes:
+- apiVersion: gateway.networking.k8s.io/v1
+  kind: HTTPRoute
+  metadata:
+    creationTimestamp: null
+    name: httproute-invalid-header
+    namespace: default
+  spec:
+    hostnames:
+    - gateway.envoyproxy.io
+    parentRefs:
+    - name: gateway-1
+      namespace: envoy-gateway
+      sectionName: http
+    rules:
+    - backendRefs:
+      - name: service-1
+        port: 8080
+      filters:
+      - extensionRef:
+          group: gateway.envoyproxy.io
+          kind: HTTPRouteFilter
+          name: invalid-header
+        type: ExtensionRef
+      matches:
+      - path:
+          value: /invalid-header
+  status:
+    parents:
+    - conditions:
+      - lastTransitionTime: null
+        message: Header must be set when rewrite path type is "Header"
+        reason: UnsupportedValue
+        status: "False"
+        type: Accepted
+      - lastTransitionTime: null
+        message: Resolved all the Object references for the Route
+        reason: ResolvedRefs
+        status: "True"
+        type: ResolvedRefs
+      controllerName: gateway.envoyproxy.io/gatewayclass-controller
+      parentRef:
+        name: gateway-1
+        namespace: envoy-gateway
+        sectionName: http
+- apiVersion: gateway.networking.k8s.io/v1
+  kind: HTTPRoute
+  metadata:
+    creationTimestamp: null
+    name: httproute-multiple-host-rewrites-1
+    namespace: default
+  spec:
+    hostnames:
+    - gateway.envoyproxy.io
+    parentRefs:
+    - name: gateway-1
+      namespace: envoy-gateway
+      sectionName: http
+    rules:
+    - backendRefs:
+      - name: service-1
+        port: 8080
+      filters:
+      - extensionRef:
+          group: gateway.envoyproxy.io
+          kind: HTTPRouteFilter
+          name: valid-header
+        type: ExtensionRef
+      - type: URLRewrite
+        urlRewrite:
+          hostname: rewrite.com
+      matches:
+      - path:
+          value: /ext-first
+  status:
+    parents:
+    - conditions:
+      - lastTransitionTime: null
+        message: Cannot configure multiple urlRewrite filters for a single HTTPRouteRule
+        reason: UnsupportedValue
+        status: "False"
+        type: Accepted
+      - lastTransitionTime: null
+        message: Resolved all the Object references for the Route
+        reason: ResolvedRefs
+        status: "True"
+        type: ResolvedRefs
+      controllerName: gateway.envoyproxy.io/gatewayclass-controller
+      parentRef:
+        name: gateway-1
+        namespace: envoy-gateway
+        sectionName: http
+- apiVersion: gateway.networking.k8s.io/v1
+  kind: HTTPRoute
+  metadata:
+    creationTimestamp: null
+    name: httproute-multiple-path-rewrites-2
+    namespace: default
+  spec:
+    hostnames:
+    - gateway.envoyproxy.io
+    parentRefs:
+    - name: gateway-1
+      namespace: envoy-gateway
+      sectionName: http
+    rules:
+    - backendRefs:
+      - name: service-1
+        port: 8080
+      filters:
+      - type: URLRewrite
+        urlRewrite:
+          hostname: rewrite.com
+      - extensionRef:
+          group: gateway.envoyproxy.io
+          kind: HTTPRouteFilter
+          name: valid-header
+        type: ExtensionRef
+      matches:
+      - path:
+          value: /inline-first
+  status:
+    parents:
+    - conditions:
+      - lastTransitionTime: null
+        message: Cannot configure multiple urlRewrite filters for a single HTTPRouteRule
+        reason: UnsupportedValue
+        status: "False"
+        type: Accepted
+      - lastTransitionTime: null
+        message: Resolved all the Object references for the Route
+        reason: ResolvedRefs
+        status: "True"
+        type: ResolvedRefs
+      controllerName: gateway.envoyproxy.io/gatewayclass-controller
+      parentRef:
+        name: gateway-1
+        namespace: envoy-gateway
+        sectionName: http
+- apiVersion: gateway.networking.k8s.io/v1
+  kind: HTTPRoute
+  metadata:
+    creationTimestamp: null
+    name: httproute-multiple-header-host-rewrites
+    namespace: default
+  spec:
+    hostnames:
+    - gateway.envoyproxy.io
+    parentRefs:
+    - name: gateway-1
+      namespace: envoy-gateway
+      sectionName: http
+    rules:
+    - backendRefs:
+      - name: service-1
+        port: 8080
+      filters:
+      - extensionRef:
+          group: gateway.envoyproxy.io
+          kind: HTTPRouteFilter
+          name: valid-header
+        type: ExtensionRef
+      - extensionRef:
+          group: gateway.envoyproxy.io
+          kind: HTTPRouteFilter
+          name: valid-header-2
+        type: ExtensionRef
+      matches:
+      - path:
+          value: /two-headers
+  status:
+    parents:
+    - conditions:
+      - lastTransitionTime: null
+        message: Cannot configure multiple urlRewrite filters for a single HTTPRouteRule
+        reason: UnsupportedValue
+        status: "False"
+        type: Accepted
+      - lastTransitionTime: null
+        message: Resolved all the Object references for the Route
+        reason: ResolvedRefs
+        status: "True"
+        type: ResolvedRefs
+      controllerName: gateway.envoyproxy.io/gatewayclass-controller
+      parentRef:
+        name: gateway-1
+        namespace: envoy-gateway
+        sectionName: http
+- apiVersion: gateway.networking.k8s.io/v1
+  kind: HTTPRoute
+  metadata:
+    creationTimestamp: null
+    name: httproute-multiple-header-host-rewrites
+    namespace: default
+  spec:
+    hostnames:
+    - gateway.envoyproxy.io
+    parentRefs:
+    - name: gateway-1
+      namespace: envoy-gateway
+      sectionName: http
+    rules:
+    - backendRefs:
+      - name: service-1
+        port: 8080
+      filters:
+      - extensionRef:
+          group: gateway.envoyproxy.io
+          kind: HTTPRouteFilter
+          name: valid-backend
+        type: ExtensionRef
+      - extensionRef:
+          group: gateway.envoyproxy.io
+          kind: HTTPRouteFilter
+          name: valid-backend-2
+        type: ExtensionRef
+      matches:
+      - path:
+          value: /two-backends
+  status:
+    parents:
+    - conditions:
+      - lastTransitionTime: null
+        message: Cannot configure multiple urlRewrite filters for a single HTTPRouteRule
+        reason: UnsupportedValue
+        status: "False"
+        type: Accepted
+      - lastTransitionTime: null
+        message: Resolved all the Object references for the Route
+        reason: ResolvedRefs
+        status: "True"
+        type: ResolvedRefs
+      controllerName: gateway.envoyproxy.io/gatewayclass-controller
+      parentRef:
+        name: gateway-1
+        namespace: envoy-gateway
+        sectionName: http
+- apiVersion: gateway.networking.k8s.io/v1
+  kind: HTTPRoute
+  metadata:
+    creationTimestamp: null
+    name: httproute-header-and-backend-host-rewrites
+    namespace: default
+  spec:
+    hostnames:
+    - gateway.envoyproxy.io
+    parentRefs:
+    - name: gateway-1
+      namespace: envoy-gateway
+      sectionName: http
+    rules:
+    - backendRefs:
+      - name: service-1
+        port: 8080
+      filters:
+      - extensionRef:
+          group: gateway.envoyproxy.io
+          kind: HTTPRouteFilter
+          name: valid-header
+        type: ExtensionRef
+      - extensionRef:
+          group: gateway.envoyproxy.io
+          kind: HTTPRouteFilter
+          name: valid-header
+        type: ExtensionRef
+      matches:
+      - path:
+          value: /header-and-backend
+  status:
+    parents:
+    - conditions:
+      - lastTransitionTime: null
+        message: Cannot configure multiple urlRewrite filters for a single HTTPRouteRule
+        reason: UnsupportedValue
+        status: "False"
+        type: Accepted
+      - lastTransitionTime: null
+        message: Resolved all the Object references for the Route
+        reason: ResolvedRefs
+        status: "True"
+        type: ResolvedRefs
+      controllerName: gateway.envoyproxy.io/gatewayclass-controller
+      parentRef:
+        name: gateway-1
+        namespace: envoy-gateway
+        sectionName: http
+infraIR:
+  envoy-gateway/gateway-1:
+    proxy:
+      listeners:
+      - address: null
+        name: envoy-gateway/gateway-1/http
+        ports:
+        - containerPort: 10080
+          name: http-80
+          protocol: HTTP
+          servicePort: 80
+      metadata:
+        labels:
+          gateway.envoyproxy.io/owning-gateway-name: gateway-1
+          gateway.envoyproxy.io/owning-gateway-namespace: envoy-gateway
+      name: envoy-gateway/gateway-1
+xdsIR:
+  envoy-gateway/gateway-1:
+    accessLog:
+      text:
+      - path: /dev/stdout
+    http:
+    - address: 0.0.0.0
+      hostnames:
+      - '*.envoyproxy.io'
+      isHTTP2: false
+      metadata:
+        kind: Gateway
+        name: gateway-1
+        namespace: envoy-gateway
+        sectionName: http
+      name: envoy-gateway/gateway-1/http
+      path:
+        escapedSlashesAction: UnescapeAndRedirect
+        mergeSlashes: true
+      port: 10080
diff --git a/internal/gatewayapi/testdata/httproute-with-urlrewrite-hostname-filter.in.yaml b/internal/gatewayapi/testdata/httproute-with-urlrewrite-hostname-filter.in.yaml
new file mode 100644
index 000000000..f39c951e5
--- /dev/null
+++ b/internal/gatewayapi/testdata/httproute-with-urlrewrite-hostname-filter.in.yaml
@@ -0,0 +1,147 @@
+gateways:
+- apiVersion: gateway.networking.k8s.io/v1
+  kind: Gateway
+  metadata:
+    namespace: envoy-gateway
+    name: gateway-1
+  spec:
+    gatewayClassName: envoy-gateway-class
+    listeners:
+    - name: http
+      protocol: HTTP
+      port: 80
+      hostname: "*.envoyproxy.io"
+      allowedRoutes:
+        namespaces:
+          from: All
+httpRoutes:
+- apiVersion: gateway.networking.k8s.io/v1
+  kind: HTTPRoute
+  metadata:
+    namespace: default
+    name: httproute-1
+  spec:
+    hostnames:
+    - gateway.envoyproxy.io
+    parentRefs:
+    - namespace: envoy-gateway
+      name: gateway-1
+      sectionName: http
+    rules:
+    - matches:
+      - path:
+          value: "/valid-header"
+      backendRefs:
+      - name: service-1
+        port: 8080
+      filters:
+      - type: ExtensionRef
+        extensionRef:
+          group: gateway.envoyproxy.io
+          kind: HTTPRouteFilter
+          name: valid-header
+- apiVersion: gateway.networking.k8s.io/v1
+  kind: HTTPRoute
+  metadata:
+    namespace: default
+    name: httproute-2
+  spec:
+    hostnames:
+    - gateway.envoyproxy.io
+    parentRefs:
+    - namespace: envoy-gateway
+      name: gateway-1
+      sectionName: http
+    rules:
+    - matches:
+      - path:
+          value: "/valid-backend"
+      backendRefs:
+      - name: service-1
+        port: 8080
+      filters:
+      - type: ExtensionRef
+        extensionRef:
+          group: gateway.envoyproxy.io
+          kind: HTTPRouteFilter
+          name: valid-backend
+- apiVersion: gateway.networking.k8s.io/v1
+  kind: HTTPRoute
+  metadata:
+    namespace: default
+    name: httproute-3
+  spec:
+    hostnames:
+    - gateway.envoyproxy.io
+    parentRefs:
+    - namespace: envoy-gateway
+      name: gateway-1
+      sectionName: http
+    rules:
+    - matches:
+      - path:
+          value: "/path-and-header-host"
+      backendRefs:
+      - name: service-1
+        port: 8080
+      filters:
+      - type: URLRewrite
+        urlRewrite:
+          path:
+            type: ReplacePrefixMatch
+            replacePrefixMatch: /rewrite
+      - type: ExtensionRef
+        extensionRef:
+          group: gateway.envoyproxy.io
+          kind: HTTPRouteFilter
+          name: valid-header
+- apiVersion: gateway.networking.k8s.io/v1
+  kind: HTTPRoute
+  metadata:
+    namespace: default
+    name: httproute-4
+  spec:
+    hostnames:
+    - gateway.envoyproxy.io
+    parentRefs:
+    - namespace: envoy-gateway
+      name: gateway-1
+      sectionName: http
+    rules:
+    - matches:
+      - path:
+          value: "/header-host-and-path"
+      backendRefs:
+      - name: service-1
+        port: 8080
+      filters:
+      - type: ExtensionRef
+        extensionRef:
+          group: gateway.envoyproxy.io
+          kind: HTTPRouteFilter
+          name: valid-header
+      - type: URLRewrite
+        urlRewrite:
+          path:
+            type: ReplacePrefixMatch
+            replacePrefixMatch: /rewrite
+httpFilters:
+- apiVersion: gateway.envoyproxy.io/v1alpha1
+  kind: HTTPRouteFilter
+  metadata:
+    name: valid-header
+    namespace: default
+  spec:
+    urlRewrite:
+      hostname:
+        type: Header
+        header: my-host
+- apiVersion: gateway.envoyproxy.io/v1alpha1
+  kind: HTTPRouteFilter
+  metadata:
+    name: valid-backend
+    namespace: default
+  spec:
+    urlRewrite:
+      hostname:
+        type: Backend
diff --git a/internal/gatewayapi/testdata/httproute-with-urlrewrite-hostname-filter.out.yaml b/internal/gatewayapi/testdata/httproute-with-urlrewrite-hostname-filter.out.yaml
new file mode 100644
index 000000000..916f7d0ce
--- /dev/null
+++ b/internal/gatewayapi/testdata/httproute-with-urlrewrite-hostname-filter.out.yaml
@@ -0,0 +1,362 @@
+gateways:
+- apiVersion: gateway.networking.k8s.io/v1
+  kind: Gateway
+  metadata:
+    creationTimestamp: null
+    name: gateway-1
+    namespace: envoy-gateway
+  spec:
+    gatewayClassName: envoy-gateway-class
+    listeners:
+    - allowedRoutes:
+        namespaces:
+          from: All
+      hostname: '*.envoyproxy.io'
+      name: http
+      port: 80
+      protocol: HTTP
+  status:
+    listeners:
+    - attachedRoutes: 4
+      conditions:
+      - lastTransitionTime: null
+        message: Sending translated listener configuration to the data plane
+        reason: Programmed
+        status: "True"
+        type: Programmed
+      - lastTransitionTime: null
+        message: Listener has been successfully translated
+        reason: Accepted
+        status: "True"
+        type: Accepted
+      - lastTransitionTime: null
+        message: Listener references have been resolved
+        reason: ResolvedRefs
+        status: "True"
+        type: ResolvedRefs
+      name: http
+      supportedKinds:
+      - group: gateway.networking.k8s.io
+        kind: HTTPRoute
+      - group: gateway.networking.k8s.io
+        kind: GRPCRoute
+httpRoutes:
+- apiVersion: gateway.networking.k8s.io/v1
+  kind: HTTPRoute
+  metadata:
+    creationTimestamp: null
+    name: httproute-1
+    namespace: default
+  spec:
+    hostnames:
+    - gateway.envoyproxy.io
+    parentRefs:
+    - name: gateway-1
+      namespace: envoy-gateway
+      sectionName: http
+    rules:
+    - backendRefs:
+      - name: service-1
+        port: 8080
+      filters:
+      - extensionRef:
+          group: gateway.envoyproxy.io
+          kind: HTTPRouteFilter
+          name: valid-header
+        type: ExtensionRef
+      matches:
+      - path:
+          value: /valid-header
+  status:
+    parents:
+    - conditions:
+      - lastTransitionTime: null
+        message: Route is accepted
+        reason: Accepted
+        status: "True"
+        type: Accepted
+      - lastTransitionTime: null
+        message: Resolved all the Object references for the Route
+        reason: ResolvedRefs
+        status: "True"
+        type: ResolvedRefs
+      controllerName: gateway.envoyproxy.io/gatewayclass-controller
+      parentRef:
+        name: gateway-1
+        namespace: envoy-gateway
+        sectionName: http
+- apiVersion: gateway.networking.k8s.io/v1
+  kind: HTTPRoute
+  metadata:
+    creationTimestamp: null
+    name: httproute-2
+    namespace: default
+  spec:
+    hostnames:
+    - gateway.envoyproxy.io
+    parentRefs:
+    - name: gateway-1
+      namespace: envoy-gateway
+      sectionName: http
+    rules:
+    - backendRefs:
+      - name: service-1
+        port: 8080
+      filters:
+      - extensionRef:
+          group: gateway.envoyproxy.io
+          kind: HTTPRouteFilter
+          name: valid-backend
+        type: ExtensionRef
+      matches:
+      - path:
+          value: /valid-backend
+  status:
+    parents:
+    - conditions:
+      - lastTransitionTime: null
+        message: Route is accepted
+        reason: Accepted
+        status: "True"
+        type: Accepted
+      - lastTransitionTime: null
+        message: Resolved all the Object references for the Route
+        reason: ResolvedRefs
+        status: "True"
+        type: ResolvedRefs
+      controllerName: gateway.envoyproxy.io/gatewayclass-controller
+      parentRef:
+        name: gateway-1
+        namespace: envoy-gateway
+        sectionName: http
+- apiVersion: gateway.networking.k8s.io/v1
+  kind: HTTPRoute
+  metadata:
+    creationTimestamp: null
+    name: httproute-3
+    namespace: default
+  spec:
+    hostnames:
+    - gateway.envoyproxy.io
+    parentRefs:
+    - name: gateway-1
+      namespace: envoy-gateway
+      sectionName: http
+    rules:
+    - backendRefs:
+      - name: service-1
+        port: 8080
+      filters:
+      - type: URLRewrite
+        urlRewrite:
+          path:
+            replacePrefixMatch: /rewrite
+            type: ReplacePrefixMatch
+      - extensionRef:
+          group: gateway.envoyproxy.io
+          kind: HTTPRouteFilter
+          name: valid-header
+        type: ExtensionRef
+      matches:
+      - path:
+          value: /path-and-header-host
+  status:
+    parents:
+    - conditions:
+      - lastTransitionTime: null
+        message: Route is accepted
+        reason: Accepted
+        status: "True"
+        type: Accepted
+      - lastTransitionTime: null
+        message: Resolved all the Object references for the Route
+        reason: ResolvedRefs
+        status: "True"
+        type: ResolvedRefs
+      controllerName: gateway.envoyproxy.io/gatewayclass-controller
+      parentRef:
+        name: gateway-1
+        namespace: envoy-gateway
+        sectionName: http
+- apiVersion: gateway.networking.k8s.io/v1
+  kind: HTTPRoute
+  metadata:
+    creationTimestamp: null
+    name: httproute-4
+    namespace: default
+  spec:
+    hostnames:
+    - gateway.envoyproxy.io
+    parentRefs:
+    - name: gateway-1
+      namespace: envoy-gateway
+      sectionName: http
+    rules:
+    - backendRefs:
+      - name: service-1
+        port: 8080
+      filters:
+      - extensionRef:
+          group: gateway.envoyproxy.io
+          kind: HTTPRouteFilter
+          name: valid-header
+        type: ExtensionRef
+      - type: URLRewrite
+        urlRewrite:
+          path:
+            replacePrefixMatch: /rewrite
+            type: ReplacePrefixMatch
+      matches:
+      - path:
+          value: /header-host-and-path
+  status:
+    parents:
+    - conditions:
+      - lastTransitionTime: null
+        message: Route is accepted
+        reason: Accepted
+        status: "True"
+        type: Accepted
+      - lastTransitionTime: null
+        message: Resolved all the Object references for the Route
+        reason: ResolvedRefs
+        status: "True"
+        type: ResolvedRefs
+      controllerName: gateway.envoyproxy.io/gatewayclass-controller
+      parentRef:
+        name: gateway-1
+        namespace: envoy-gateway
+        sectionName: http
+infraIR:
+  envoy-gateway/gateway-1:
+    proxy:
+      listeners:
+      - address: null
+        name: envoy-gateway/gateway-1/http
+        ports:
+        - containerPort: 10080
+          name: http-80
+          protocol: HTTP
+          servicePort: 80
+      metadata:
+        labels:
+          gateway.envoyproxy.io/owning-gateway-name: gateway-1
+          gateway.envoyproxy.io/owning-gateway-namespace: envoy-gateway
+      name: envoy-gateway/gateway-1
+xdsIR:
+  envoy-gateway/gateway-1:
+    accessLog:
+      text:
+      - path: /dev/stdout
+    http:
+    - address: 0.0.0.0
+      hostnames:
+      - '*.envoyproxy.io'
+      isHTTP2: false
+      metadata:
+        kind: Gateway
+        name: gateway-1
+        namespace: envoy-gateway
+        sectionName: http
+      name: envoy-gateway/gateway-1/http
+      path:
+        escapedSlashesAction: UnescapeAndRedirect
+        mergeSlashes: true
+      port: 10080
+      routes:
+      - destination:
+          name: httproute/default/httproute-3/rule/0
+          settings:
+          - addressType: IP
+            endpoints:
+            - host: 7.7.7.7
+              port: 8080
+            protocol: HTTP
+            weight: 1
+        hostname: gateway.envoyproxy.io
+        isHTTP2: false
+        metadata:
+          kind: HTTPRoute
+          name: httproute-3
+          namespace: default
+        name: httproute/default/httproute-3/rule/0/match/0/gateway_envoyproxy_io
+        pathMatch:
+          distinct: false
+          name: ""
+          prefix: /path-and-header-host
+        urlRewrite:
+          host:
+            header: my-host
+          path:
+            fullReplace: null
+            prefixMatchReplace: /rewrite
+      - destination:
+          name: httproute/default/httproute-4/rule/0
+          settings:
+          - addressType: IP
+            endpoints:
+            - host: 7.7.7.7
+              port: 8080
+            protocol: HTTP
+            weight: 1
+        hostname: gateway.envoyproxy.io
+        isHTTP2: false
+        metadata:
+          kind: HTTPRoute
+          name: httproute-4
+          namespace: default
+        name: httproute/default/httproute-4/rule/0/match/0/gateway_envoyproxy_io
+        pathMatch:
+          distinct: false
+          name: ""
+          prefix: /header-host-and-path
+        urlRewrite:
+          path:
+            fullReplace: null
+            prefixMatchReplace: /rewrite
+      - destination:
+          name: httproute/default/httproute-2/rule/0
+          settings:
+          - addressType: IP
+            endpoints:
+            - host: 7.7.7.7
+              port: 8080
+            protocol: HTTP
+            weight: 1
+        hostname: gateway.envoyproxy.io
+        isHTTP2: false
+        metadata:
+          kind: HTTPRoute
+          name: httproute-2
+          namespace: default
+        name: httproute/default/httproute-2/rule/0/match/0/gateway_envoyproxy_io
+        pathMatch:
+          distinct: false
+          name: ""
+          prefix: /valid-backend
+        urlRewrite:
+          host:
+            backend: true
+      - destination:
+          name: httproute/default/httproute-1/rule/0
+          settings:
+          - addressType: IP
+            endpoints:
+            - host: 7.7.7.7
+              port: 8080
+            protocol: HTTP
+            weight: 1
+        hostname: gateway.envoyproxy.io
+        isHTTP2: false
+        metadata:
+          kind: HTTPRoute
+          name: httproute-1
+          namespace: default
+        name: httproute/default/httproute-1/rule/0/match/0/gateway_envoyproxy_io
+        pathMatch:
+          distinct: false
+          name: ""
+          prefix: /valid-header
+        urlRewrite:
+          host:
+            header: my-host
diff --git a/internal/ir/xds_test.go b/internal/ir/xds_test.go
index 5ff9a8736..b45931525 100644
--- a/internal/ir/xds_test.go
+++ b/internal/ir/xds_test.go
@@ -308,7 +308,9 @@ var (
 			Exact: ptr.To("rewrite"),
 		},
 		URLRewrite: &URLRewrite{
-			Hostname: ptr.To("rewrite.example.com"),
+			Host: &HTTPHostModifier{
+				Name: ptr.To("rewrite.example.com"),
+			},
 			Path: &ExtendedHTTPPathModifier{
 				HTTPPathModifier: HTTPPathModifier{
 					FullReplace: ptr.To("/rewrite"),
@@ -324,7 +326,9 @@ var (
 			Exact: ptr.To("rewrite"),
 		},
 		URLRewrite: &URLRewrite{
-			Hostname: ptr.To("rewrite.example.com"),
+			Host: &HTTPHostModifier{
+				Name: ptr.To("rewrite.example.com"),
+			},
 			Path: &ExtendedHTTPPathModifier{
 				HTTPPathModifier: HTTPPathModifier{
 					FullReplace:        ptr.To("/rewrite"),
diff --git a/internal/xds/translator/testdata/in/xds-ir/http-route-rewrite-url-host.yaml b/internal/xds/translator/testdata/in/xds-ir/http-route-rewrite-url-host.yaml
index 8cc673a7e..525a22210 100644
--- a/internal/xds/translator/testdata/in/xds-ir/http-route-rewrite-url-host.yaml
+++ b/internal/xds/translator/testdata/in/xds-ir/http-route-rewrite-url-host.yaml
@@ -23,6 +23,43 @@ http:
         - host: "1.2.3.4"
           port: 50000
     urlRewrite:
-      hostname: "3.3.3.3"
+      host:
+        name: "3.3.3.3"
+      path:
+        prefixMatchReplace: /rewrite
+  - name: "rewrite-host-header"
+    pathMatch:
+      prefix: "/host-header"
+    hostname: gateway.envoyproxy.io
+    headerMatches:
+    - name: ":authority"
+      exact: gateway.envoyproxy.io
+    destination:
+      name: "rewrite-route-dest"
+      settings:
+      - endpoints:
+        - host: "1.2.3.4"
+          port: 50000
+    urlRewrite:
+      host:
+        header: "foo"
+      path:
+        prefixMatchReplace: /rewrite
+  - name: "rewrite-host-backend"
+    pathMatch:
+      prefix: "/host-backend"
+    hostname: gateway.envoyproxy.io
+    headerMatches:
+    - name: ":authority"
+      exact: gateway.envoyproxy.io
+    destination:
+      name: "rewrite-route-dest"
+      settings:
+      - endpoints:
+        - host: "1.2.3.4"
+          port: 50000
+    urlRewrite:
+      host:
+        backend: true
       path:
         prefixMatchReplace: /rewrite
diff --git a/internal/xds/translator/testdata/out/xds-ir/http-route-rewrite-url-host.routes.yaml b/internal/xds/translator/testdata/out/xds-ir/http-route-rewrite-url-host.routes.yaml
index 680a67404..a3e1e29e8 100644
--- a/internal/xds/translator/testdata/out/xds-ir/http-route-rewrite-url-host.routes.yaml
+++ b/internal/xds/translator/testdata/out/xds-ir/http-route-rewrite-url-host.routes.yaml
@@ -19,3 +19,31 @@
         prefixRewrite: /rewrite
         upgradeConfigs:
         - upgradeType: websocket
+    - match:
+        headers:
+        - name: :authority
+          stringMatch:
+            exact: gateway.envoyproxy.io
+        pathSeparatedPrefix: /host-header
+      name: rewrite-host-header
+      route:
+        appendXForwardedHost: true
+        cluster: rewrite-route-dest
+        hostRewriteHeader: foo
+        prefixRewrite: /rewrite
+        upgradeConfigs:
+        - upgradeType: websocket
+    - match:
+        headers:
+        - name: :authority
+          stringMatch:
+            exact: gateway.envoyproxy.io
+        pathSeparatedPrefix: /host-backend
+      name: rewrite-host-backend
+      route:
+        appendXForwardedHost: true
+        autoHostRewrite: true
+        cluster: rewrite-route-dest
+        prefixRewrite: /rewrite
+        upgradeConfigs:
+        - upgradeType: websocket
diff --git a/site/content/en/latest/api/extension_types.md b/site/content/en/latest/api/extension_types.md
index c183a4f0b..f90ee0702 100644
--- a/site/content/en/latest/api/extension_types.md
+++ b/site/content/en/latest/api/extension_types.md
@@ -1971,7 +1971,7 @@ _Appears in:_
 | Field | Type | Required | Description |
 | ---   | ---  | ---      | ---         |
 | `type` | _[HTTPHostnameModifierType](#httphostnamemodifiertype)_ |  true  |  |
-| `setFromHeader` | _string_ |  false  | SetFromHeader is the name of the header whose value would be used to rewrite the Host header |
+| `header` | _string_ |  false  | Header is the name of the header whose value would be used to rewrite the Host header |
 
 
 #### HTTPHostnameModifierType
@@ -1985,8 +1985,8 @@ _Appears in:_
 
 | Value | Description |
 | ----- | ----------- |
-| `SetFromHeader` | HeaderHTTPHostnameModifier indicates that the Host header value would be replaced with the value of the header specified in setFromHeader.<br />https://www.envoyproxy.io/docs/envoy/latest/api-v3/config/route/v3/route_components.proto#envoy-v3-api-field-config-route-v3-routeaction-host-rewrite-header<br /> | 
-| `SetFromBackend` | BackendHTTPHostnameModifier indicates that the Host header value would be replaced by the DNS name of the backend if it exists.<br />https://www.envoyproxy.io/docs/envoy/latest/api-v3/config/route/v3/route_components.proto#envoy-v3-api-field-config-route-v3-routeaction-auto-host-rewrite<br /> | 
+| `Header` | HeaderHTTPHostnameModifier indicates that the Host header value would be replaced with the value of the header specified in header.<br />https://www.envoyproxy.io/docs/envoy/latest/api-v3/config/route/v3/route_components.proto#envoy-v3-api-field-config-route-v3-routeaction-host-rewrite-header<br /> | 
+| `Backend` | BackendHTTPHostnameModifier indicates that the Host header value would be replaced by the DNS name of the backend if it exists.<br />https://www.envoyproxy.io/docs/envoy/latest/api-v3/config/route/v3/route_components.proto#envoy-v3-api-field-config-route-v3-routeaction-auto-host-rewrite<br /> | 
 
 
 #### HTTPPathModifier
@@ -2106,6 +2106,7 @@ _Appears in:_
 
 | Field | Type | Required | Description |
 | ---   | ---  | ---      | ---         |
+| `hostname` | _[HTTPHostnameModifier](#httphostnamemodifier)_ |  false  | Hostname is the value to be used to replace the Host header value during<br />forwarding. |
 | `path` | _[HTTPPathModifier](#httppathmodifier)_ |  false  | Path defines a path rewrite. |
 
 
diff --git a/site/content/en/latest/tasks/traffic/http-urlrewrite.md b/site/content/en/latest/tasks/traffic/http-urlrewrite.md
index a643d775a..3515bd9ca 100644
--- a/site/content/en/latest/tasks/traffic/http-urlrewrite.md
+++ b/site/content/en/latest/tasks/traffic/http-urlrewrite.md
@@ -374,14 +374,14 @@ spec:
 The HTTPRoute status should indicate that it has been accepted and is bound to the example Gateway.
 
 ```shell
-kubectl get httproute/http-filter-url-rewrite -o yaml
+kubectl get httproute/http-filter-url-regex-rewrite -o yaml
 ```
 
-Querying `http://${GATEWAY_HOST}/get/origin/path/extra` should rewrite the request to
-`http://${GATEWAY_HOST}/force/replace/fullpath`.
+Querying `http://${GATEWAY_HOST}/service/foo/v1/api` should rewrite the request to
+`http://${GATEWAY_HOST}/service/foo/v1/api`.
 
 ```console
-$ curl -L -vvv --header "Host: path.regex.rewrite.example" "http://${GATEWAY_HOST}/get/origin/path/extra"
+$ curl -L -vvv --header "Host: path.regex.rewrite.example" "http://${GATEWAY_HOST}/service/foo/v1/api"
 ...
 > GET /service/foo/v1/api HTTP/1.1
 > Host: path.regex.rewrite.example
@@ -555,6 +555,145 @@ $ curl -L -vvv --header "Host: path.rewrite.example" "http://${GATEWAY_HOST}/get
 
 You can see that the `X-Forwarded-Host` is `path.rewrite.example`, but the actual host is `envoygateway.io`.
 
+## Rewrite URL Host Name by Header or Backend
+
+In addition to core Gateway-API rewrite options, Envoy Gateway supports extended rewrite options through the [HTTPRouteFilter][] API.
+The `HTTPRouteFilter` API can be configured to rewrite the Host header value to:
+- The value of a different request header
+- The DNS name of the backend that the request is routed to
+
+In the following example, the host header is rewritten to the value of the x-custom-host header. 
+
+{{< tabpane text=true >}}
+{{% tab header="Apply from stdin" %}}
+
+```shell
+cat <<EOF | kubectl apply -f -
+apiVersion: gateway.networking.k8s.io/v1
+kind: HTTPRoute
+metadata:
+  name: http-filter-hostname-header-rewrite
+spec:
+  parentRefs:
+    - name: eg
+  hostnames:
+    - host.header.rewrite.example
+  rules:
+    - matches:
+      - path:
+          type: PathPrefix
+          value: "/header"
+      filters:
+        - type: ExtensionRef
+          extensionRef:
+            group: gateway.envoyproxy.io
+            kind: HTTPRouteFilter
+            name: header-host-rewrite
+      backendRefs:
+      - name: backend
+        port: 3000
+---
+apiVersion: gateway.envoyproxy.io/v1alpha1
+kind: HTTPRouteFilter
+metadata:
+  name: header-host-rewrite
+spec:
+  urlRewrite:
+    hostname:
+      type: Header
+      header: x-custom-host      
+EOF
+```
+
+{{% /tab %}}
+{{% tab header="Apply from file" %}}
+Save and apply the following resource to your cluster:
+
+```yaml
+---
+apiVersion: gateway.networking.k8s.io/v1
+kind: HTTPRoute
+metadata:
+  name: http-filter-hostname-header-rewrite
+spec:
+  parentRefs:
+    - name: eg
+  hostnames:
+    - host.header.rewrite.example
+  rules:
+    - matches:
+        - path:
+            type: PathPrefix
+            value: "/header"
+      filters:
+        - type: ExtensionRef
+          extensionRef:
+            group: gateway.envoyproxy.io
+            kind: HTTPRouteFilter
+            name: header-host-rewrite
+      backendRefs:
+        - name: backend
+          port: 3000
+---
+apiVersion: gateway.envoyproxy.io/v1alpha1
+kind: HTTPRouteFilter
+metadata:
+  name: header-host-rewrite
+spec:
+  urlRewrite:
+    hostname:
+      type: Header
+      header: x-custom-host   
+```
+
+{{% /tab %}}
+{{< /tabpane >}}
+
+The HTTPRoute status should indicate that it has been accepted and is bound to the example Gateway.
+
+```shell
+kubectl get httproute/http-filter-header-host-rewrite -o yaml
+```
+
+Querying `http://${GATEWAY_HOST}/header` and providing a custom host rewrite header x-custom-host should rewrite the 
+request host header to the value of the x-custom-host header.
+
+```console
+$ curl -L -vvv --header "Host: host.header.rewrite.example" --header "x-custom-host: foo" "http://${GATEWAY_HOST}/header"
+...
+> GET /header HTTP/1.1
+> Host: host.header.rewrite.example
+> User-Agent: curl/8.7.1
+> Accept: */*
+> x-custom-host: foo
+>
+* Request completely sent off
+< HTTP/1.1 200 OK
+<
+{
+ "path": "/header",
+ "host": "foo",
+ "method": "GET",
+ "proto": "HTTP/1.1",
+ "headers": {
+  "X-Custom-Host": [
+   "foo"
+  ],
+  "X-Forwarded-Host": [
+   "host.header.rewrite.example"
+  ],
+ },
+ "namespace": "default",
+ "ingress": "",
+ "service": "",
+ "pod": "backend-765694d47f-5t6f2"
+...
+```
+
+You can see that the host is rewritten from `host.header.rewrite.example`, to the value of the provided 
+`x-custom-host` header `foo`. The original host header is preserved in the `X-Forwarded-Host` header. 
+
+
 [HTTPURLRewriteFilter]: https://gateway-api.sigs.k8s.io/reference/spec/#gateway.networking.k8s.io/v1.HTTPURLRewriteFilter
 [HTTPRouteFilter]: ../../../api/extension_types#httproutefilter
 [RE2]: https://github.com/google/re2/wiki/Syntax
\ No newline at end of file
diff --git a/site/content/zh/latest/api/extension_types.md b/site/content/zh/latest/api/extension_types.md
index c183a4f0b..f90ee0702 100644
--- a/site/content/zh/latest/api/extension_types.md
+++ b/site/content/zh/latest/api/extension_types.md
@@ -1971,7 +1971,7 @@ _Appears in:_
 | Field | Type | Required | Description |
 | ---   | ---  | ---      | ---         |
 | `type` | _[HTTPHostnameModifierType](#httphostnamemodifiertype)_ |  true  |  |
-| `setFromHeader` | _string_ |  false  | SetFromHeader is the name of the header whose value would be used to rewrite the Host header |
+| `header` | _string_ |  false  | Header is the name of the header whose value would be used to rewrite the Host header |
 
 
 #### HTTPHostnameModifierType
@@ -1985,8 +1985,8 @@ _Appears in:_
 
 | Value | Description |
 | ----- | ----------- |
-| `SetFromHeader` | HeaderHTTPHostnameModifier indicates that the Host header value would be replaced with the value of the header specified in setFromHeader.<br />https://www.envoyproxy.io/docs/envoy/latest/api-v3/config/route/v3/route_components.proto#envoy-v3-api-field-config-route-v3-routeaction-host-rewrite-header<br /> | 
-| `SetFromBackend` | BackendHTTPHostnameModifier indicates that the Host header value would be replaced by the DNS name of the backend if it exists.<br />https://www.envoyproxy.io/docs/envoy/latest/api-v3/config/route/v3/route_components.proto#envoy-v3-api-field-config-route-v3-routeaction-auto-host-rewrite<br /> | 
+| `Header` | HeaderHTTPHostnameModifier indicates that the Host header value would be replaced with the value of the header specified in header.<br />https://www.envoyproxy.io/docs/envoy/latest/api-v3/config/route/v3/route_components.proto#envoy-v3-api-field-config-route-v3-routeaction-host-rewrite-header<br /> | 
+| `Backend` | BackendHTTPHostnameModifier indicates that the Host header value would be replaced by the DNS name of the backend if it exists.<br />https://www.envoyproxy.io/docs/envoy/latest/api-v3/config/route/v3/route_components.proto#envoy-v3-api-field-config-route-v3-routeaction-auto-host-rewrite<br /> | 
 
 
 #### HTTPPathModifier
@@ -2106,6 +2106,7 @@ _Appears in:_
 
 | Field | Type | Required | Description |
 | ---   | ---  | ---      | ---         |
+| `hostname` | _[HTTPHostnameModifier](#httphostnamemodifier)_ |  false  | Hostname is the value to be used to replace the Host header value during<br />forwarding. |
 | `path` | _[HTTPPathModifier](#httppathmodifier)_ |  false  | Path defines a path rewrite. |
 
 
diff --git a/test/benchmark/tests/scale_httproutes.go b/test/benchmark/tests/scale_httproutes.go
index cf0839220..1431032bc 100644
--- a/test/benchmark/tests/scale_httproutes.go
+++ b/test/benchmark/tests/scale_httproutes.go
@@ -44,7 +44,7 @@ var ScaleHTTPRoutes = suite.BenchmarkTest{
 		require.NoError(t, err)
 
 		routeNameFormat := "benchmark-route-%d"
-		routeScales := []uint16{10, 50, 100, 300, 500}
+		routeScales := []uint16{10, 50, 100, 300, 500, 1000}
 		routeScalesN := len(routeScales)
 		routeNNs := make([]types.NamespacedName, 0, routeScales[routeScalesN-1])
 
diff --git a/test/cel-validation/httproutefilter_test.go b/test/cel-validation/httproutefilter_test.go
index 7f84deb71..c0b6e1ec8 100644
--- a/test/cel-validation/httproutefilter_test.go
+++ b/test/cel-validation/httproutefilter_test.go
@@ -86,13 +86,13 @@ func TestHTTPRouteFilter(t *testing.T) {
 			},
 		},
 		{
-			desc: "Valid SetFromHeader",
+			desc: "Valid Header",
 			mutate: func(httproutefilter *egv1a1.HTTPRouteFilter) {
 				httproutefilter.Spec = egv1a1.HTTPRouteFilterSpec{
 					URLRewrite: &egv1a1.HTTPURLRewriteFilter{
 						Hostname: &egv1a1.HTTPHostnameModifier{
-							Type:          egv1a1.HeaderHTTPHostnameModifier,
-							SetFromHeader: ptr.To("foo"),
+							Type:   egv1a1.HeaderHTTPHostnameModifier,
+							Header: ptr.To("foo"),
 						},
 					},
 				}
@@ -113,7 +113,7 @@ func TestHTTPRouteFilter(t *testing.T) {
 			wantErrors: []string{},
 		},
 		{
-			desc: "invalid SetFromHeader missing settings",
+			desc: "invalid Header missing settings",
 			mutate: func(httproutefilter *egv1a1.HTTPRouteFilter) {
 				httproutefilter.Spec = egv1a1.HTTPRouteFilterSpec{
 					URLRewrite: &egv1a1.HTTPURLRewriteFilter{
@@ -123,7 +123,7 @@ func TestHTTPRouteFilter(t *testing.T) {
 					},
 				}
 			},
-			wantErrors: []string{"spec.urlRewrite.hostname: Invalid value: \"object\": setFromHeader must be specified for SetFromHeader type"},
+			wantErrors: []string{"spec.urlRewrite.hostname: Invalid value: \"object\": header must be specified for Header type"},
 		},
 		{
 			desc: "invalid SetFromBackend type",
@@ -131,13 +131,13 @@ func TestHTTPRouteFilter(t *testing.T) {
 				httproutefilter.Spec = egv1a1.HTTPRouteFilterSpec{
 					URLRewrite: &egv1a1.HTTPURLRewriteFilter{
 						Hostname: &egv1a1.HTTPHostnameModifier{
-							Type:          egv1a1.BackendHTTPHostnameModifier,
-							SetFromHeader: ptr.To("foo"),
+							Type:   egv1a1.BackendHTTPHostnameModifier,
+							Header: ptr.To("foo"),
 						},
 					},
 				}
 			},
-			wantErrors: []string{"spec.urlRewrite.hostname: Invalid value: \"object\": setFromHeader must be nil if the type is not SetFromHeader"},
+			wantErrors: []string{"spec.urlRewrite.hostname: Invalid value: \"object\": header must be nil if the type is not Header"},
 		},
 	}
 
diff --git a/test/e2e/testdata/httproute-rewrite-host.yaml b/test/e2e/testdata/httproute-rewrite-host.yaml
new file mode 100644
index 000000000..871b2008b
--- /dev/null
+++ b/test/e2e/testdata/httproute-rewrite-host.yaml
@@ -0,0 +1,68 @@
+apiVersion: gateway.networking.k8s.io/v1
+kind: HTTPRoute
+metadata:
+  name: rewrite-host
+  namespace: gateway-conformance-infra
+spec:
+  parentRefs:
+  - name: same-namespace
+  rules:
+  - matches:
+    - path:
+        type: PathPrefix
+        value: /header
+    filters:
+    - type: ExtensionRef
+      extensionRef:
+        group: gateway.envoyproxy.io
+        kind: HTTPRouteFilter
+        name: header-host-rewrite
+    backendRefs:
+    - name: infra-backend-v1
+      port: 8080
+  - matches:
+    - path:
+        type: PathPrefix
+        value: /backend
+    filters:
+    - type: ExtensionRef
+      extensionRef:
+        group: gateway.envoyproxy.io
+        kind: HTTPRouteFilter
+        name: backend-host-rewrite
+    backendRefs:
+    - group: gateway.envoyproxy.io
+      kind: Backend
+      name: backend-fqdn
+---
+apiVersion: gateway.envoyproxy.io/v1alpha1
+kind: HTTPRouteFilter
+metadata:
+  name: header-host-rewrite
+  namespace: gateway-conformance-infra
+spec:
+  urlRewrite:
+    hostname:
+      type: Header
+      header: x-custom-host
+---
+apiVersion: gateway.envoyproxy.io/v1alpha1
+kind: HTTPRouteFilter
+metadata:
+  name: backend-host-rewrite
+  namespace: gateway-conformance-infra
+spec:
+  urlRewrite:
+    hostname:
+      type: Backend
+---
+apiVersion: gateway.envoyproxy.io/v1alpha1
+kind: Backend
+metadata:
+  name: backend-fqdn
+  namespace: gateway-conformance-infra
+spec:
+  endpoints:
+  - fqdn:
+      hostname: infra-backend-v1.gateway-conformance-infra.svc.cluster.local
+      port: 8080
diff --git a/test/e2e/tests/httproute_rewrite_host.go b/test/e2e/tests/httproute_rewrite_host.go
new file mode 100644
index 000000000..643d0891e
--- /dev/null
+++ b/test/e2e/tests/httproute_rewrite_host.go
@@ -0,0 +1,75 @@
+// Copyright Envoy Gateway Authors
+// SPDX-License-Identifier: Apache-2.0
+// The full text of the Apache license is available in the LICENSE file at
+// the root of the repo.
+
+//go:build e2e
+
+package tests
+
+import (
+	"testing"
+
+	"k8s.io/apimachinery/pkg/types"
+	"sigs.k8s.io/gateway-api/conformance/utils/http"
+	"sigs.k8s.io/gateway-api/conformance/utils/kubernetes"
+	"sigs.k8s.io/gateway-api/conformance/utils/suite"
+)
+
+func init() {
+	ConformanceTests = append(ConformanceTests, HTTPRouteRewriteHostHeader)
+}
+
+var HTTPRouteRewriteHostHeader = suite.ConformanceTest{
+	ShortName:   "HTTPRouteRewriteHostHeader",
+	Description: "An HTTPRoute with host rewrite filter to rewrite a host header",
+	Manifests:   []string{"testdata/httproute-rewrite-host.yaml"},
+	Test: func(t *testing.T, suite *suite.ConformanceTestSuite) {
+		ns := "gateway-conformance-infra"
+		routeNN := types.NamespacedName{Name: "rewrite-host", Namespace: ns}
+		gwNN := types.NamespacedName{Name: "same-namespace", Namespace: ns}
+		gwAddr := kubernetes.GatewayAndHTTPRoutesMustBeAccepted(t, suite.Client, suite.TimeoutConfig, suite.ControllerName, kubernetes.NewGatewayRef(gwNN), routeNN)
+		kubernetes.HTTPRouteMustHaveResolvedRefsConditionsTrue(t, suite.Client, suite.TimeoutConfig, routeNN, gwNN)
+
+		testCases := []http.ExpectedResponse{
+			{
+				Request: http.Request{
+					Path: "/header",
+					Headers: map[string]string{
+						"x-custom-host": "custom-host",
+					},
+				},
+				ExpectedRequest: &http.ExpectedRequest{
+					Request: http.Request{
+						Path: "/header",
+						Host: "custom-host",
+					},
+				},
+				Backend:   "infra-backend-v1",
+				Namespace: ns,
+			},
+			{
+				Request: http.Request{
+					Path: "/backend",
+				},
+				ExpectedRequest: &http.ExpectedRequest{
+					Request: http.Request{
+						Path: "/backend",
+						Host: "infra-backend-v1.gateway-conformance-infra.svc.cluster.local",
+					},
+				},
+				Backend:   "infra-backend-v1",
+				Namespace: ns,
+			},
+		}
+		for i := range testCases {
+			// Declare tc here to avoid loop variable
+			// reuse issues across parallel tests.
+			tc := testCases[i]
+			t.Run(tc.GetTestCaseName(i), func(t *testing.T) {
+				t.Parallel()
+				http.MakeRequestAndExpectEventuallyConsistentResponse(t, suite.RoundTripper, suite.TimeoutConfig, gwAddr, tc)
+			})
+		}
+	},
+}