From bc4403cdc5775345e7b0ff6298b06126b3c71414 Mon Sep 17 00:00:00 2001 From: Liam White Date: Fri, 15 May 2026 15:02:18 -0700 Subject: [PATCH 1/7] networking: add prefix_rewrite and uri_regex_rewrite to HTTPRedirect Extends HTTPRedirect to support prefix-aware path manipulation on redirect responses, exposing Envoy's existing prefix_rewrite and regex_rewrite capabilities in RedirectAction. Previously, HTTPRedirect.uri replaced the entire path regardless of the route match type. This adds two new mutually-exclusive fields: - prefix_rewrite: replaces the matched route prefix with the given value, enabling /foo/bar -> /baz/bar style redirects - uri_regex_rewrite: rewrites the path using RE2 regex with capture group substitution for complex transformations Both are mutually exclusive with the existing uri field. Validation is enforced in the istio/istio control plane. --- networking/v1alpha3/virtual_service.pb.go | 168 ++++++++++++++++---- networking/v1alpha3/virtual_service.pb.html | 31 ++++ networking/v1alpha3/virtual_service.proto | 49 ++++++ 3 files changed, 214 insertions(+), 34 deletions(-) diff --git a/networking/v1alpha3/virtual_service.pb.go b/networking/v1alpha3/virtual_service.pb.go index d4db2ab0c6..07480888e2 100644 --- a/networking/v1alpha3/virtual_service.pb.go +++ b/networking/v1alpha3/virtual_service.pb.go @@ -2021,11 +2021,40 @@ func (x *TLSMatchAttributes) GetSourceNamespace() string { // ... // // ``` +// +// The following rule redirects requests with a path prefix of /foo to the +// authority foo.example.com, stripping the /foo prefix from the path: +// +// ```yaml +// apiVersion: networking.istio.io/v1 +// kind: VirtualService +// metadata: +// +// name: foo-redirect +// +// spec: +// +// hosts: +// - example.com +// http: +// - match: +// - uri: +// prefix: /foo/ +// redirect: +// authority: foo.example.com +// prefix_rewrite: / +// +// ``` +// +// With this rule, a request to example.com/foo/bar is redirected to +// foo.example.com/bar. type HTTPRedirect struct { state protoimpl.MessageState `protogen:"open.v1"` // On a redirect, overwrite the Path portion of the URL with this // value. Note that the entire path will be replaced, irrespective of the // request URI being matched as an exact path or prefix. + // + // Mutually exclusive with prefix_rewrite and uri_regex_rewrite. Uri string `protobuf:"bytes,1,opt,name=uri,proto3" json:"uri,omitempty"` // On a redirect, overwrite the Authority/Host portion of the URL with // this value. @@ -2042,9 +2071,17 @@ type HTTPRedirect struct { Scheme string `protobuf:"bytes,6,opt,name=scheme,proto3" json:"scheme,omitempty"` // On a redirect, Specifies the HTTP status code to use in the redirect // response. The default response code is MOVED_PERMANENTLY (301). - RedirectCode uint32 `protobuf:"varint,3,opt,name=redirect_code,json=redirectCode,proto3" json:"redirect_code,omitempty"` - unknownFields protoimpl.UnknownFields - sizeCache protoimpl.SizeCache + RedirectCode uint32 `protobuf:"varint,3,opt,name=redirect_code,json=redirectCode,proto3" json:"redirect_code,omitempty"` + // Specifies how to rewrite the path on redirect. Exactly one of uri, + // prefix_rewrite, or uri_regex_rewrite may be set. + // + // Types that are valid to be assigned to PathRewriteSpecifier: + // + // *HTTPRedirect_PrefixRewrite + // *HTTPRedirect_UriRegexRewrite + PathRewriteSpecifier isHTTPRedirect_PathRewriteSpecifier `protobuf_oneof:"path_rewrite_specifier"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache } func (x *HTTPRedirect) Reset() { @@ -2130,6 +2167,31 @@ func (x *HTTPRedirect) GetRedirectCode() uint32 { return 0 } +func (x *HTTPRedirect) GetPathRewriteSpecifier() isHTTPRedirect_PathRewriteSpecifier { + if x != nil { + return x.PathRewriteSpecifier + } + return nil +} + +func (x *HTTPRedirect) GetPrefixRewrite() string { + if x != nil { + if x, ok := x.PathRewriteSpecifier.(*HTTPRedirect_PrefixRewrite); ok { + return x.PrefixRewrite + } + } + return "" +} + +func (x *HTTPRedirect) GetUriRegexRewrite() *RegexRewrite { + if x != nil { + if x, ok := x.PathRewriteSpecifier.(*HTTPRedirect_UriRegexRewrite); ok { + return x.UriRegexRewrite + } + } + return nil +} + type isHTTPRedirect_RedirectPort interface { isHTTPRedirect_RedirectPort() } @@ -2150,6 +2212,38 @@ func (*HTTPRedirect_Port) isHTTPRedirect_RedirectPort() {} func (*HTTPRedirect_DerivePort) isHTTPRedirect_RedirectPort() {} +type isHTTPRedirect_PathRewriteSpecifier interface { + isHTTPRedirect_PathRewriteSpecifier() +} + +type HTTPRedirect_PrefixRewrite struct { + // On a redirect, replace the matched prefix (or the entire path for exact + // matches) with this value. The route match must use a prefix match type. + // The matched prefix is stripped from the path and this value is prepended. + // + // Examples (route prefix match: /foo): + // - prefix_rewrite: /bar → /foo/baz becomes /bar/baz + // - prefix_rewrite: / → /foo/baz becomes //baz (use /foo/ match to get /baz) + // + // Mutually exclusive with uri and uri_regex_rewrite. + PrefixRewrite string `protobuf:"bytes,7,opt,name=prefix_rewrite,json=prefixRewrite,proto3,oneof"` +} + +type HTTPRedirect_UriRegexRewrite struct { + // On a redirect, rewrite the path portion of the URI with the specified + // RE2 regex. Capture groups in the pattern may be referenced in the + // replacement string. + // + // Example: match "^/foo(/.*)$" with rewrite "\\1" rewrites /foo/bar to /bar. + // + // Mutually exclusive with uri and prefix_rewrite. + UriRegexRewrite *RegexRewrite `protobuf:"bytes,8,opt,name=uri_regex_rewrite,json=uriRegexRewrite,proto3,oneof"` +} + +func (*HTTPRedirect_PrefixRewrite) isHTTPRedirect_PathRewriteSpecifier() {} + +func (*HTTPRedirect_UriRegexRewrite) isHTTPRedirect_PathRewriteSpecifier() {} + // HTTPDirectResponse can be used to send a fixed response to clients. // For example, the following rule returns a fixed 503 status with a body // to requests for /v1/getProductRatings API. @@ -3622,7 +3716,7 @@ const file_networking_v1alpha3_virtual_service_proto_rawDesc = "" + "\x10source_namespace\x18\a \x01(\tR\x0fsourceNamespace\x1a?\n" + "\x11SourceLabelsEntry\x12\x10\n" + "\x03key\x18\x01 \x01(\tR\x03key\x12\x14\n" + - "\x05value\x18\x02 \x01(\tR\x05value:\x028\x01J\x04\b\x04\x10\x05R\rsource_subnet\"\xcf\x02\n" + + "\x05value\x18\x02 \x01(\tR\x05value:\x028\x01J\x04\b\x04\x10\x05R\rsource_subnet\"\xe9\x03\n" + "\fHTTPRedirect\x12\x10\n" + "\x03uri\x18\x01 \x01(\tR\x03uri\x12\x1c\n" + "\tauthority\x18\x02 \x01(\tR\tauthority\x12\x14\n" + @@ -3630,11 +3724,14 @@ const file_networking_v1alpha3_virtual_service_proto_rawDesc = "" + "\vderive_port\x18\x05 \x01(\x0e2=.istio.networking.v1alpha3.HTTPRedirect.RedirectPortSelectionH\x00R\n" + "derivePort\x12\x16\n" + "\x06scheme\x18\x06 \x01(\tR\x06scheme\x12#\n" + - "\rredirect_code\x18\x03 \x01(\rR\fredirectCode\"I\n" + + "\rredirect_code\x18\x03 \x01(\rR\fredirectCode\x12'\n" + + "\x0eprefix_rewrite\x18\a \x01(\tH\x01R\rprefixRewrite\x12U\n" + + "\x11uri_regex_rewrite\x18\b \x01(\v2'.istio.networking.v1alpha3.RegexRewriteH\x01R\x0furiRegexRewrite\"I\n" + "\x15RedirectPortSelection\x12\x19\n" + "\x15FROM_PROTOCOL_DEFAULT\x10\x00\x12\x15\n" + "\x11FROM_REQUEST_PORT\x10\x01B\x0f\n" + - "\rredirect_port\"k\n" + + "\rredirect_portB\x18\n" + + "\x16path_rewrite_specifier\"k\n" + "\x12HTTPDirectResponse\x12\x1c\n" + "\x06status\x18\x01 \x01(\rB\x04\xe2A\x01\x02R\x06status\x127\n" + "\x04body\x18\x02 \x01(\v2#.istio.networking.v1alpha3.HTTPBodyR\x04body\"I\n" + @@ -3807,34 +3904,35 @@ var file_networking_v1alpha3_virtual_service_proto_depIdxs = []int32{ 33, // 36: istio.networking.v1alpha3.L4MatchAttributes.source_labels:type_name -> istio.networking.v1alpha3.L4MatchAttributes.SourceLabelsEntry 34, // 37: istio.networking.v1alpha3.TLSMatchAttributes.source_labels:type_name -> istio.networking.v1alpha3.TLSMatchAttributes.SourceLabelsEntry 0, // 38: istio.networking.v1alpha3.HTTPRedirect.derive_port:type_name -> istio.networking.v1alpha3.HTTPRedirect.RedirectPortSelection - 16, // 39: istio.networking.v1alpha3.HTTPDirectResponse.body:type_name -> istio.networking.v1alpha3.HTTPBody - 18, // 40: istio.networking.v1alpha3.HTTPRewrite.uri_regex_rewrite:type_name -> istio.networking.v1alpha3.RegexRewrite - 37, // 41: istio.networking.v1alpha3.HTTPRetry.per_try_timeout:type_name -> google.protobuf.Duration - 39, // 42: istio.networking.v1alpha3.HTTPRetry.retry_remote_localities:type_name -> google.protobuf.BoolValue - 39, // 43: istio.networking.v1alpha3.HTTPRetry.retry_ignore_previous_hosts:type_name -> google.protobuf.BoolValue - 37, // 44: istio.networking.v1alpha3.HTTPRetry.backoff:type_name -> google.protobuf.Duration - 19, // 45: istio.networking.v1alpha3.CorsPolicy.allow_origins:type_name -> istio.networking.v1alpha3.StringMatch - 37, // 46: istio.networking.v1alpha3.CorsPolicy.max_age:type_name -> google.protobuf.Duration - 39, // 47: istio.networking.v1alpha3.CorsPolicy.allow_credentials:type_name -> google.protobuf.BoolValue - 1, // 48: istio.networking.v1alpha3.CorsPolicy.unmatched_preflights:type_name -> istio.networking.v1alpha3.CorsPolicy.UnmatchedPreflights - 35, // 49: istio.networking.v1alpha3.HTTPFaultInjection.delay:type_name -> istio.networking.v1alpha3.HTTPFaultInjection.Delay - 36, // 50: istio.networking.v1alpha3.HTTPFaultInjection.abort:type_name -> istio.networking.v1alpha3.HTTPFaultInjection.Abort - 3, // 51: istio.networking.v1alpha3.HTTPMirrorPolicy.destination:type_name -> istio.networking.v1alpha3.Destination - 25, // 52: istio.networking.v1alpha3.HTTPMirrorPolicy.percentage:type_name -> istio.networking.v1alpha3.Percent - 27, // 53: istio.networking.v1alpha3.Headers.HeaderOperations.set:type_name -> istio.networking.v1alpha3.Headers.HeaderOperations.SetEntry - 28, // 54: istio.networking.v1alpha3.Headers.HeaderOperations.add:type_name -> istio.networking.v1alpha3.Headers.HeaderOperations.AddEntry - 19, // 55: istio.networking.v1alpha3.HTTPMatchRequest.HeadersEntry.value:type_name -> istio.networking.v1alpha3.StringMatch - 19, // 56: istio.networking.v1alpha3.HTTPMatchRequest.QueryParamsEntry.value:type_name -> istio.networking.v1alpha3.StringMatch - 19, // 57: istio.networking.v1alpha3.HTTPMatchRequest.WithoutHeadersEntry.value:type_name -> istio.networking.v1alpha3.StringMatch - 37, // 58: istio.networking.v1alpha3.HTTPFaultInjection.Delay.fixed_delay:type_name -> google.protobuf.Duration - 37, // 59: istio.networking.v1alpha3.HTTPFaultInjection.Delay.exponential_delay:type_name -> google.protobuf.Duration - 25, // 60: istio.networking.v1alpha3.HTTPFaultInjection.Delay.percentage:type_name -> istio.networking.v1alpha3.Percent - 25, // 61: istio.networking.v1alpha3.HTTPFaultInjection.Abort.percentage:type_name -> istio.networking.v1alpha3.Percent - 62, // [62:62] is the sub-list for method output_type - 62, // [62:62] is the sub-list for method input_type - 62, // [62:62] is the sub-list for extension type_name - 62, // [62:62] is the sub-list for extension extendee - 0, // [0:62] is the sub-list for field type_name + 18, // 39: istio.networking.v1alpha3.HTTPRedirect.uri_regex_rewrite:type_name -> istio.networking.v1alpha3.RegexRewrite + 16, // 40: istio.networking.v1alpha3.HTTPDirectResponse.body:type_name -> istio.networking.v1alpha3.HTTPBody + 18, // 41: istio.networking.v1alpha3.HTTPRewrite.uri_regex_rewrite:type_name -> istio.networking.v1alpha3.RegexRewrite + 37, // 42: istio.networking.v1alpha3.HTTPRetry.per_try_timeout:type_name -> google.protobuf.Duration + 39, // 43: istio.networking.v1alpha3.HTTPRetry.retry_remote_localities:type_name -> google.protobuf.BoolValue + 39, // 44: istio.networking.v1alpha3.HTTPRetry.retry_ignore_previous_hosts:type_name -> google.protobuf.BoolValue + 37, // 45: istio.networking.v1alpha3.HTTPRetry.backoff:type_name -> google.protobuf.Duration + 19, // 46: istio.networking.v1alpha3.CorsPolicy.allow_origins:type_name -> istio.networking.v1alpha3.StringMatch + 37, // 47: istio.networking.v1alpha3.CorsPolicy.max_age:type_name -> google.protobuf.Duration + 39, // 48: istio.networking.v1alpha3.CorsPolicy.allow_credentials:type_name -> google.protobuf.BoolValue + 1, // 49: istio.networking.v1alpha3.CorsPolicy.unmatched_preflights:type_name -> istio.networking.v1alpha3.CorsPolicy.UnmatchedPreflights + 35, // 50: istio.networking.v1alpha3.HTTPFaultInjection.delay:type_name -> istio.networking.v1alpha3.HTTPFaultInjection.Delay + 36, // 51: istio.networking.v1alpha3.HTTPFaultInjection.abort:type_name -> istio.networking.v1alpha3.HTTPFaultInjection.Abort + 3, // 52: istio.networking.v1alpha3.HTTPMirrorPolicy.destination:type_name -> istio.networking.v1alpha3.Destination + 25, // 53: istio.networking.v1alpha3.HTTPMirrorPolicy.percentage:type_name -> istio.networking.v1alpha3.Percent + 27, // 54: istio.networking.v1alpha3.Headers.HeaderOperations.set:type_name -> istio.networking.v1alpha3.Headers.HeaderOperations.SetEntry + 28, // 55: istio.networking.v1alpha3.Headers.HeaderOperations.add:type_name -> istio.networking.v1alpha3.Headers.HeaderOperations.AddEntry + 19, // 56: istio.networking.v1alpha3.HTTPMatchRequest.HeadersEntry.value:type_name -> istio.networking.v1alpha3.StringMatch + 19, // 57: istio.networking.v1alpha3.HTTPMatchRequest.QueryParamsEntry.value:type_name -> istio.networking.v1alpha3.StringMatch + 19, // 58: istio.networking.v1alpha3.HTTPMatchRequest.WithoutHeadersEntry.value:type_name -> istio.networking.v1alpha3.StringMatch + 37, // 59: istio.networking.v1alpha3.HTTPFaultInjection.Delay.fixed_delay:type_name -> google.protobuf.Duration + 37, // 60: istio.networking.v1alpha3.HTTPFaultInjection.Delay.exponential_delay:type_name -> google.protobuf.Duration + 25, // 61: istio.networking.v1alpha3.HTTPFaultInjection.Delay.percentage:type_name -> istio.networking.v1alpha3.Percent + 25, // 62: istio.networking.v1alpha3.HTTPFaultInjection.Abort.percentage:type_name -> istio.networking.v1alpha3.Percent + 63, // [63:63] is the sub-list for method output_type + 63, // [63:63] is the sub-list for method input_type + 63, // [63:63] is the sub-list for extension type_name + 63, // [63:63] is the sub-list for extension extendee + 0, // [0:63] is the sub-list for field type_name } func init() { file_networking_v1alpha3_virtual_service_proto_init() } @@ -3845,6 +3943,8 @@ func file_networking_v1alpha3_virtual_service_proto_init() { file_networking_v1alpha3_virtual_service_proto_msgTypes[12].OneofWrappers = []any{ (*HTTPRedirect_Port)(nil), (*HTTPRedirect_DerivePort)(nil), + (*HTTPRedirect_PrefixRewrite)(nil), + (*HTTPRedirect_UriRegexRewrite)(nil), } file_networking_v1alpha3_virtual_service_proto_msgTypes[14].OneofWrappers = []any{ (*HTTPBody_String_)(nil), diff --git a/networking/v1alpha3/virtual_service.pb.html b/networking/v1alpha3/virtual_service.pb.html index 637a497cc1..eadbc2be77 100644 --- a/networking/v1alpha3/virtual_service.pb.html +++ b/networking/v1alpha3/virtual_service.pb.html @@ -1525,6 +1525,7 @@

HTTPRedirect

On a redirect, overwrite the Path portion of the URL with this value. Note that the entire path will be replaced, irrespective of the request URI being matched as an exact path or prefix.

+

Mutually exclusive with prefixRewrite and uriRegexRewrite.

@@ -1580,6 +1581,36 @@

HTTPRedirect

On a redirect, Specifies the HTTP status code to use in the redirect response. The default response code is MOVED_PERMANENTLY (301).

+ + + +
+
string (oneof)
+
+ +

On a redirect, replace the matched route prefix with this value. The route +match must use a prefix match type. The matched prefix is stripped from the +path and this value is prepended.

+

Examples (route prefix match: /foo):

+ +

Mutually exclusive with uri and uriRegexRewrite.

+ + + + +
+ +
+ +

On a redirect, rewrite the path portion of the URI with the specified +RE2 regex. Capture groups in the pattern may be referenced in the +replacement string.

+

Example: match ^/foo(/.*)$ with rewrite \1 rewrites /foo/bar to /bar.

+

Mutually exclusive with uri and prefixRewrite.

+ diff --git a/networking/v1alpha3/virtual_service.proto b/networking/v1alpha3/virtual_service.proto index d81ad2d72c..700c0c2cff 100644 --- a/networking/v1alpha3/virtual_service.proto +++ b/networking/v1alpha3/virtual_service.proto @@ -1074,10 +1074,35 @@ message TLSMatchAttributes { // ... // ``` // +// The following rule redirects requests with a path prefix of /foo to the +// authority foo.example.com, stripping the /foo prefix from the path: +// +// ```yaml +// apiVersion: networking.istio.io/v1 +// kind: VirtualService +// metadata: +// name: foo-redirect +// spec: +// hosts: +// - example.com +// http: +// - match: +// - uri: +// prefix: /foo/ +// redirect: +// authority: foo.example.com +// prefix_rewrite: / +// ``` +// +// With this rule, a request to example.com/foo/bar is redirected to +// foo.example.com/bar. +// message HTTPRedirect { // On a redirect, overwrite the Path portion of the URL with this // value. Note that the entire path will be replaced, irrespective of the // request URI being matched as an exact path or prefix. + // + // Mutually exclusive with prefix_rewrite and uri_regex_rewrite. string uri = 1; // On a redirect, overwrite the Authority/Host portion of the URL with @@ -1106,6 +1131,30 @@ message HTTPRedirect { // On a redirect, Specifies the HTTP status code to use in the redirect // response. The default response code is MOVED_PERMANENTLY (301). uint32 redirect_code = 3; + + // Specifies how to rewrite the path on redirect. Exactly one of uri, + // prefix_rewrite, or uri_regex_rewrite may be set. + oneof path_rewrite_specifier { + // On a redirect, replace the matched prefix (or the entire path for exact + // matches) with this value. The route match must use a prefix match type. + // The matched prefix is stripped from the path and this value is prepended. + // + // Examples (route prefix match: /foo): + // - prefix_rewrite: /bar → /foo/baz becomes /bar/baz + // - prefix_rewrite: / → /foo/baz becomes //baz (use /foo/ match to get /baz) + // + // Mutually exclusive with uri and uri_regex_rewrite. + string prefix_rewrite = 7; + + // On a redirect, rewrite the path portion of the URI with the specified + // RE2 regex. Capture groups in the pattern may be referenced in the + // replacement string. + // + // Example: match "^/foo(/.*)$" with rewrite "\\1" rewrites /foo/bar to /bar. + // + // Mutually exclusive with uri and prefix_rewrite. + RegexRewrite uri_regex_rewrite = 8; + } } // HTTPDirectResponse can be used to send a fixed response to clients. From 63448e49842546d3d7e2bbbc27bdb8181ca05c60 Mon Sep 17 00:00:00 2001 From: Liam White Date: Fri, 15 May 2026 23:41:15 -0700 Subject: [PATCH 2/7] releasenotes: add note for HTTPRedirect prefix_rewrite and uri_regex_rewrite --- releasenotes/notes/redirect-prefix-rewrite.yaml | 14 ++++++++++++++ 1 file changed, 14 insertions(+) create mode 100644 releasenotes/notes/redirect-prefix-rewrite.yaml diff --git a/releasenotes/notes/redirect-prefix-rewrite.yaml b/releasenotes/notes/redirect-prefix-rewrite.yaml new file mode 100644 index 0000000000..78ee66577d --- /dev/null +++ b/releasenotes/notes/redirect-prefix-rewrite.yaml @@ -0,0 +1,14 @@ +apiVersion: release-notes/v2 +kind: feature +area: traffic-management +issue: + - 47500 + - 47777 + - 52521 + +releaseNotes: + - | + **Added** `prefix_rewrite` and `uri_regex_rewrite` fields to `HTTPRedirect`, allowing redirects + that preserve the path suffix. `prefix_rewrite` replaces only the matched route prefix (e.g. + `example.com/foo/bar` → `foo.example.com/bar`); `uri_regex_rewrite` applies an RE2 regex + substitution. Both are mutually exclusive with the existing `uri` field. From 4d70b90bf8a62450ce7bc4b5bf2fd2fce36934ce Mon Sep 17 00:00:00 2001 From: Liam White Date: Sat, 16 May 2026 14:13:40 -0700 Subject: [PATCH 3/7] gen: regenerate files for HTTPRedirect prefix_rewrite and uri_regex_rewrite --- kubernetes/customresourcedefinitions.gen.yaml | 150 ++++++++++++++---- networking/v1/virtual_service_alias.gen.go | 47 ++++++ networking/v1alpha3/virtual_service.pb.html | 37 +++-- .../v1beta1/virtual_service_alias.gen.go | 47 ++++++ 4 files changed, 239 insertions(+), 42 deletions(-) diff --git a/kubernetes/customresourcedefinitions.gen.yaml b/kubernetes/customresourcedefinitions.gen.yaml index 7318e07ffd..08e49dde23 100644 --- a/kubernetes/customresourcedefinitions.gen.yaml +++ b/kubernetes/customresourcedefinitions.gen.yaml @@ -11523,19 +11523,31 @@ spec: description: The name assigned to the route for debugging purposes. type: string redirect: + allOf: + - oneOf: + - not: + anyOf: + - required: + - port + - required: + - derivePort + - required: + - port + - required: + - derivePort + - oneOf: + - not: + anyOf: + - required: + - prefixRewrite + - required: + - uriRegexRewrite + - required: + - prefixRewrite + - required: + - uriRegexRewrite description: A HTTP rule can either return a direct_response, redirect or forward (default) traffic. - oneOf: - - not: - anyOf: - - required: - - port - - required: - - derivePort - - required: - - port - - required: - - derivePort properties: authority: description: On a redirect, overwrite the Authority/Host @@ -11556,6 +11568,10 @@ spec: maximum: 4294967295 minimum: 0 type: integer + prefixRewrite: + description: On a redirect, replace the matched prefix (or + the entire path for exact matches) with this value. + type: string redirectCode: description: On a redirect, Specifies the HTTP status code to use in the redirect response. @@ -11570,6 +11586,18 @@ spec: description: On a redirect, overwrite the Path portion of the URL with this value. type: string + uriRegexRewrite: + description: On a redirect, rewrite the path portion of + the URI with the specified RE2 regex. + properties: + match: + description: '[RE2 style regex-based match](https://github.com/google/re2/wiki/Syntax).' + type: string + rewrite: + description: The string that should replace into matching + portions of original URI. + type: string + type: object type: object retries: description: Retry policy for HTTP requests. @@ -12575,19 +12603,31 @@ spec: description: The name assigned to the route for debugging purposes. type: string redirect: + allOf: + - oneOf: + - not: + anyOf: + - required: + - port + - required: + - derivePort + - required: + - port + - required: + - derivePort + - oneOf: + - not: + anyOf: + - required: + - prefixRewrite + - required: + - uriRegexRewrite + - required: + - prefixRewrite + - required: + - uriRegexRewrite description: A HTTP rule can either return a direct_response, redirect or forward (default) traffic. - oneOf: - - not: - anyOf: - - required: - - port - - required: - - derivePort - - required: - - port - - required: - - derivePort properties: authority: description: On a redirect, overwrite the Authority/Host @@ -12608,6 +12648,10 @@ spec: maximum: 4294967295 minimum: 0 type: integer + prefixRewrite: + description: On a redirect, replace the matched prefix (or + the entire path for exact matches) with this value. + type: string redirectCode: description: On a redirect, Specifies the HTTP status code to use in the redirect response. @@ -12622,6 +12666,18 @@ spec: description: On a redirect, overwrite the Path portion of the URL with this value. type: string + uriRegexRewrite: + description: On a redirect, rewrite the path portion of + the URI with the specified RE2 regex. + properties: + match: + description: '[RE2 style regex-based match](https://github.com/google/re2/wiki/Syntax).' + type: string + rewrite: + description: The string that should replace into matching + portions of original URI. + type: string + type: object type: object retries: description: Retry policy for HTTP requests. @@ -13627,19 +13683,31 @@ spec: description: The name assigned to the route for debugging purposes. type: string redirect: + allOf: + - oneOf: + - not: + anyOf: + - required: + - port + - required: + - derivePort + - required: + - port + - required: + - derivePort + - oneOf: + - not: + anyOf: + - required: + - prefixRewrite + - required: + - uriRegexRewrite + - required: + - prefixRewrite + - required: + - uriRegexRewrite description: A HTTP rule can either return a direct_response, redirect or forward (default) traffic. - oneOf: - - not: - anyOf: - - required: - - port - - required: - - derivePort - - required: - - port - - required: - - derivePort properties: authority: description: On a redirect, overwrite the Authority/Host @@ -13660,6 +13728,10 @@ spec: maximum: 4294967295 minimum: 0 type: integer + prefixRewrite: + description: On a redirect, replace the matched prefix (or + the entire path for exact matches) with this value. + type: string redirectCode: description: On a redirect, Specifies the HTTP status code to use in the redirect response. @@ -13674,6 +13746,18 @@ spec: description: On a redirect, overwrite the Path portion of the URL with this value. type: string + uriRegexRewrite: + description: On a redirect, rewrite the path portion of + the URI with the specified RE2 regex. + properties: + match: + description: '[RE2 style regex-based match](https://github.com/google/re2/wiki/Syntax).' + type: string + rewrite: + description: The string that should replace into matching + portions of original URI. + type: string + type: object type: object retries: description: Retry policy for HTTP requests. diff --git a/networking/v1/virtual_service_alias.gen.go b/networking/v1/virtual_service_alias.gen.go index 2ce6d25923..0151ff8ec6 100644 --- a/networking/v1/virtual_service_alias.gen.go +++ b/networking/v1/virtual_service_alias.gen.go @@ -520,6 +520,33 @@ type TLSMatchAttributes = v1alpha3.TLSMatchAttributes // ... // // ``` +// +// The following rule redirects requests with a path prefix of /foo to the +// authority foo.example.com, stripping the /foo prefix from the path: +// +// ```yaml +// apiVersion: networking.istio.io/v1 +// kind: VirtualService +// metadata: +// +// name: foo-redirect +// +// spec: +// +// hosts: +// - example.com +// http: +// - match: +// - uri: +// prefix: /foo/ +// redirect: +// authority: foo.example.com +// prefix_rewrite: / +// +// ``` +// +// With this rule, a request to example.com/foo/bar is redirected to +// foo.example.com/bar. type HTTPRedirect = v1alpha3.HTTPRedirect type HTTPRedirect_RedirectPortSelection = v1alpha3.HTTPRedirect_RedirectPortSelection @@ -534,6 +561,26 @@ type HTTPRedirect_Port = v1alpha3.HTTPRedirect_Port // * FROM_REQUEST_PORT: automatically use the port of the request. type HTTPRedirect_DerivePort = v1alpha3.HTTPRedirect_DerivePort +// On a redirect, replace the matched prefix (or the entire path for exact +// matches) with this value. The route match must use a prefix match type. +// The matched prefix is stripped from the path and this value is prepended. +// +// Examples (route prefix match: /foo): +// - prefix_rewrite: /bar → /foo/baz becomes /bar/baz +// - prefix_rewrite: / → /foo/baz becomes //baz (use /foo/ match to get /baz) +// +// Mutually exclusive with uri and uri_regex_rewrite. +type HTTPRedirect_PrefixRewrite = v1alpha3.HTTPRedirect_PrefixRewrite + +// On a redirect, rewrite the path portion of the URI with the specified +// RE2 regex. Capture groups in the pattern may be referenced in the +// replacement string. +// +// Example: match "^/foo(/.*)$" with rewrite "\\1" rewrites /foo/bar to /bar. +// +// Mutually exclusive with uri and prefix_rewrite. +type HTTPRedirect_UriRegexRewrite = v1alpha3.HTTPRedirect_UriRegexRewrite + // HTTPDirectResponse can be used to send a fixed response to clients. // For example, the following rule returns a fixed 503 status with a body // to requests for /v1/getProductRatings API. diff --git a/networking/v1alpha3/virtual_service.pb.html b/networking/v1alpha3/virtual_service.pb.html index eadbc2be77..4c245dac40 100644 --- a/networking/v1alpha3/virtual_service.pb.html +++ b/networking/v1alpha3/virtual_service.pb.html @@ -1508,6 +1508,25 @@

HTTPRedirect

authority: newratings.default.svc.cluster.local ... +

The following rule redirects requests with a path prefix of /foo to the +authority foo.example.com, stripping the /foo prefix from the path:

+
apiVersion: networking.istio.io/v1
+kind: VirtualService
+metadata:
+  name: foo-redirect
+spec:
+  hosts:
+  - example.com
+  http:
+  - match:
+    - uri:
+        prefix: /foo/
+    redirect:
+      authority: foo.example.com
+      prefix_rewrite: /
+
+

With this rule, a request to example.com/foo/bar is redirected to +foo.example.com/bar.

@@ -1525,7 +1544,7 @@

HTTPRedirect

On a redirect, overwrite the Path portion of the URL with this value. Note that the entire path will be replaced, irrespective of the request URI being matched as an exact path or prefix.

-

Mutually exclusive with prefixRewrite and uriRegexRewrite.

+

Mutually exclusive with prefix_rewrite and uri_regex_rewrite.

@@ -1588,15 +1607,15 @@

HTTPRedirect

string (oneof)
@@ -1608,8 +1627,8 @@

HTTPRedirect

On a redirect, rewrite the path portion of the URI with the specified RE2 regex. Capture groups in the pattern may be referenced in the replacement string.

-

Example: match ^/foo(/.*)$ with rewrite \1 rewrites /foo/bar to /bar.

-

Mutually exclusive with uri and prefixRewrite.

+

Example: match “^/foo(/.*)$” with rewrite “\1” rewrites /foo/bar to /bar.

+

Mutually exclusive with uri and prefix_rewrite.

diff --git a/networking/v1beta1/virtual_service_alias.gen.go b/networking/v1beta1/virtual_service_alias.gen.go index 530098b3e5..eebe17ec8a 100644 --- a/networking/v1beta1/virtual_service_alias.gen.go +++ b/networking/v1beta1/virtual_service_alias.gen.go @@ -520,6 +520,33 @@ type TLSMatchAttributes = v1alpha3.TLSMatchAttributes // ... // // ``` +// +// The following rule redirects requests with a path prefix of /foo to the +// authority foo.example.com, stripping the /foo prefix from the path: +// +// ```yaml +// apiVersion: networking.istio.io/v1 +// kind: VirtualService +// metadata: +// +// name: foo-redirect +// +// spec: +// +// hosts: +// - example.com +// http: +// - match: +// - uri: +// prefix: /foo/ +// redirect: +// authority: foo.example.com +// prefix_rewrite: / +// +// ``` +// +// With this rule, a request to example.com/foo/bar is redirected to +// foo.example.com/bar. type HTTPRedirect = v1alpha3.HTTPRedirect type HTTPRedirect_RedirectPortSelection = v1alpha3.HTTPRedirect_RedirectPortSelection @@ -534,6 +561,26 @@ type HTTPRedirect_Port = v1alpha3.HTTPRedirect_Port // * FROM_REQUEST_PORT: automatically use the port of the request. type HTTPRedirect_DerivePort = v1alpha3.HTTPRedirect_DerivePort +// On a redirect, replace the matched prefix (or the entire path for exact +// matches) with this value. The route match must use a prefix match type. +// The matched prefix is stripped from the path and this value is prepended. +// +// Examples (route prefix match: /foo): +// - prefix_rewrite: /bar → /foo/baz becomes /bar/baz +// - prefix_rewrite: / → /foo/baz becomes //baz (use /foo/ match to get /baz) +// +// Mutually exclusive with uri and uri_regex_rewrite. +type HTTPRedirect_PrefixRewrite = v1alpha3.HTTPRedirect_PrefixRewrite + +// On a redirect, rewrite the path portion of the URI with the specified +// RE2 regex. Capture groups in the pattern may be referenced in the +// replacement string. +// +// Example: match "^/foo(/.*)$" with rewrite "\\1" rewrites /foo/bar to /bar. +// +// Mutually exclusive with uri and prefix_rewrite. +type HTTPRedirect_UriRegexRewrite = v1alpha3.HTTPRedirect_UriRegexRewrite + // HTTPDirectResponse can be used to send a fixed response to clients. // For example, the following rule returns a fixed 503 status with a body // to requests for /v1/getProductRatings API. From 8b532b4a9265e4aebf4c4ec8f51162ca2eba69ea Mon Sep 17 00:00:00 2001 From: Liam White Date: Tue, 26 May 2026 13:19:54 -0700 Subject: [PATCH 4/7] networking: remove uri_regex_rewrite from HTTPRedirect, keep prefix_rewrite only --- networking/v1alpha3/virtual_service.pb.go | 141 +++++++--------------- networking/v1alpha3/virtual_service.proto | 35 ++---- 2 files changed, 55 insertions(+), 121 deletions(-) diff --git a/networking/v1alpha3/virtual_service.pb.go b/networking/v1alpha3/virtual_service.pb.go index 07480888e2..b04dd4e812 100644 --- a/networking/v1alpha3/virtual_service.pb.go +++ b/networking/v1alpha3/virtual_service.pb.go @@ -2054,7 +2054,7 @@ type HTTPRedirect struct { // value. Note that the entire path will be replaced, irrespective of the // request URI being matched as an exact path or prefix. // - // Mutually exclusive with prefix_rewrite and uri_regex_rewrite. + // Mutually exclusive with prefix_rewrite. Uri string `protobuf:"bytes,1,opt,name=uri,proto3" json:"uri,omitempty"` // On a redirect, overwrite the Authority/Host portion of the URL with // this value. @@ -2072,16 +2072,18 @@ type HTTPRedirect struct { // On a redirect, Specifies the HTTP status code to use in the redirect // response. The default response code is MOVED_PERMANENTLY (301). RedirectCode uint32 `protobuf:"varint,3,opt,name=redirect_code,json=redirectCode,proto3" json:"redirect_code,omitempty"` - // Specifies how to rewrite the path on redirect. Exactly one of uri, - // prefix_rewrite, or uri_regex_rewrite may be set. + // On a redirect, replace the matched prefix with this value. The route match + // must use a prefix match type. The matched prefix is stripped from the path + // and this value is prepended. // - // Types that are valid to be assigned to PathRewriteSpecifier: + // Examples (route prefix match: /foo): + // - prefix_rewrite: /bar → /foo/baz becomes /bar/baz + // - prefix_rewrite: / → /foo/baz becomes //baz (use /foo/ match to get /baz) // - // *HTTPRedirect_PrefixRewrite - // *HTTPRedirect_UriRegexRewrite - PathRewriteSpecifier isHTTPRedirect_PathRewriteSpecifier `protobuf_oneof:"path_rewrite_specifier"` - unknownFields protoimpl.UnknownFields - sizeCache protoimpl.SizeCache + // Mutually exclusive with uri. + PrefixRewrite string `protobuf:"bytes,7,opt,name=prefix_rewrite,json=prefixRewrite,proto3" json:"prefix_rewrite,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache } func (x *HTTPRedirect) Reset() { @@ -2167,31 +2169,13 @@ func (x *HTTPRedirect) GetRedirectCode() uint32 { return 0 } -func (x *HTTPRedirect) GetPathRewriteSpecifier() isHTTPRedirect_PathRewriteSpecifier { - if x != nil { - return x.PathRewriteSpecifier - } - return nil -} - func (x *HTTPRedirect) GetPrefixRewrite() string { if x != nil { - if x, ok := x.PathRewriteSpecifier.(*HTTPRedirect_PrefixRewrite); ok { - return x.PrefixRewrite - } + return x.PrefixRewrite } return "" } -func (x *HTTPRedirect) GetUriRegexRewrite() *RegexRewrite { - if x != nil { - if x, ok := x.PathRewriteSpecifier.(*HTTPRedirect_UriRegexRewrite); ok { - return x.UriRegexRewrite - } - } - return nil -} - type isHTTPRedirect_RedirectPort interface { isHTTPRedirect_RedirectPort() } @@ -2212,38 +2196,6 @@ func (*HTTPRedirect_Port) isHTTPRedirect_RedirectPort() {} func (*HTTPRedirect_DerivePort) isHTTPRedirect_RedirectPort() {} -type isHTTPRedirect_PathRewriteSpecifier interface { - isHTTPRedirect_PathRewriteSpecifier() -} - -type HTTPRedirect_PrefixRewrite struct { - // On a redirect, replace the matched prefix (or the entire path for exact - // matches) with this value. The route match must use a prefix match type. - // The matched prefix is stripped from the path and this value is prepended. - // - // Examples (route prefix match: /foo): - // - prefix_rewrite: /bar → /foo/baz becomes /bar/baz - // - prefix_rewrite: / → /foo/baz becomes //baz (use /foo/ match to get /baz) - // - // Mutually exclusive with uri and uri_regex_rewrite. - PrefixRewrite string `protobuf:"bytes,7,opt,name=prefix_rewrite,json=prefixRewrite,proto3,oneof"` -} - -type HTTPRedirect_UriRegexRewrite struct { - // On a redirect, rewrite the path portion of the URI with the specified - // RE2 regex. Capture groups in the pattern may be referenced in the - // replacement string. - // - // Example: match "^/foo(/.*)$" with rewrite "\\1" rewrites /foo/bar to /bar. - // - // Mutually exclusive with uri and prefix_rewrite. - UriRegexRewrite *RegexRewrite `protobuf:"bytes,8,opt,name=uri_regex_rewrite,json=uriRegexRewrite,proto3,oneof"` -} - -func (*HTTPRedirect_PrefixRewrite) isHTTPRedirect_PathRewriteSpecifier() {} - -func (*HTTPRedirect_UriRegexRewrite) isHTTPRedirect_PathRewriteSpecifier() {} - // HTTPDirectResponse can be used to send a fixed response to clients. // For example, the following rule returns a fixed 503 status with a body // to requests for /v1/getProductRatings API. @@ -3716,7 +3668,7 @@ const file_networking_v1alpha3_virtual_service_proto_rawDesc = "" + "\x10source_namespace\x18\a \x01(\tR\x0fsourceNamespace\x1a?\n" + "\x11SourceLabelsEntry\x12\x10\n" + "\x03key\x18\x01 \x01(\tR\x03key\x12\x14\n" + - "\x05value\x18\x02 \x01(\tR\x05value:\x028\x01J\x04\b\x04\x10\x05R\rsource_subnet\"\xe9\x03\n" + + "\x05value\x18\x02 \x01(\tR\x05value:\x028\x01J\x04\b\x04\x10\x05R\rsource_subnet\"\xf6\x02\n" + "\fHTTPRedirect\x12\x10\n" + "\x03uri\x18\x01 \x01(\tR\x03uri\x12\x1c\n" + "\tauthority\x18\x02 \x01(\tR\tauthority\x12\x14\n" + @@ -3724,14 +3676,12 @@ const file_networking_v1alpha3_virtual_service_proto_rawDesc = "" + "\vderive_port\x18\x05 \x01(\x0e2=.istio.networking.v1alpha3.HTTPRedirect.RedirectPortSelectionH\x00R\n" + "derivePort\x12\x16\n" + "\x06scheme\x18\x06 \x01(\tR\x06scheme\x12#\n" + - "\rredirect_code\x18\x03 \x01(\rR\fredirectCode\x12'\n" + - "\x0eprefix_rewrite\x18\a \x01(\tH\x01R\rprefixRewrite\x12U\n" + - "\x11uri_regex_rewrite\x18\b \x01(\v2'.istio.networking.v1alpha3.RegexRewriteH\x01R\x0furiRegexRewrite\"I\n" + + "\rredirect_code\x18\x03 \x01(\rR\fredirectCode\x12%\n" + + "\x0eprefix_rewrite\x18\a \x01(\tR\rprefixRewrite\"I\n" + "\x15RedirectPortSelection\x12\x19\n" + "\x15FROM_PROTOCOL_DEFAULT\x10\x00\x12\x15\n" + "\x11FROM_REQUEST_PORT\x10\x01B\x0f\n" + - "\rredirect_portB\x18\n" + - "\x16path_rewrite_specifier\"k\n" + + "\rredirect_port\"k\n" + "\x12HTTPDirectResponse\x12\x1c\n" + "\x06status\x18\x01 \x01(\rB\x04\xe2A\x01\x02R\x06status\x127\n" + "\x04body\x18\x02 \x01(\v2#.istio.networking.v1alpha3.HTTPBodyR\x04body\"I\n" + @@ -3904,35 +3854,34 @@ var file_networking_v1alpha3_virtual_service_proto_depIdxs = []int32{ 33, // 36: istio.networking.v1alpha3.L4MatchAttributes.source_labels:type_name -> istio.networking.v1alpha3.L4MatchAttributes.SourceLabelsEntry 34, // 37: istio.networking.v1alpha3.TLSMatchAttributes.source_labels:type_name -> istio.networking.v1alpha3.TLSMatchAttributes.SourceLabelsEntry 0, // 38: istio.networking.v1alpha3.HTTPRedirect.derive_port:type_name -> istio.networking.v1alpha3.HTTPRedirect.RedirectPortSelection - 18, // 39: istio.networking.v1alpha3.HTTPRedirect.uri_regex_rewrite:type_name -> istio.networking.v1alpha3.RegexRewrite - 16, // 40: istio.networking.v1alpha3.HTTPDirectResponse.body:type_name -> istio.networking.v1alpha3.HTTPBody - 18, // 41: istio.networking.v1alpha3.HTTPRewrite.uri_regex_rewrite:type_name -> istio.networking.v1alpha3.RegexRewrite - 37, // 42: istio.networking.v1alpha3.HTTPRetry.per_try_timeout:type_name -> google.protobuf.Duration - 39, // 43: istio.networking.v1alpha3.HTTPRetry.retry_remote_localities:type_name -> google.protobuf.BoolValue - 39, // 44: istio.networking.v1alpha3.HTTPRetry.retry_ignore_previous_hosts:type_name -> google.protobuf.BoolValue - 37, // 45: istio.networking.v1alpha3.HTTPRetry.backoff:type_name -> google.protobuf.Duration - 19, // 46: istio.networking.v1alpha3.CorsPolicy.allow_origins:type_name -> istio.networking.v1alpha3.StringMatch - 37, // 47: istio.networking.v1alpha3.CorsPolicy.max_age:type_name -> google.protobuf.Duration - 39, // 48: istio.networking.v1alpha3.CorsPolicy.allow_credentials:type_name -> google.protobuf.BoolValue - 1, // 49: istio.networking.v1alpha3.CorsPolicy.unmatched_preflights:type_name -> istio.networking.v1alpha3.CorsPolicy.UnmatchedPreflights - 35, // 50: istio.networking.v1alpha3.HTTPFaultInjection.delay:type_name -> istio.networking.v1alpha3.HTTPFaultInjection.Delay - 36, // 51: istio.networking.v1alpha3.HTTPFaultInjection.abort:type_name -> istio.networking.v1alpha3.HTTPFaultInjection.Abort - 3, // 52: istio.networking.v1alpha3.HTTPMirrorPolicy.destination:type_name -> istio.networking.v1alpha3.Destination - 25, // 53: istio.networking.v1alpha3.HTTPMirrorPolicy.percentage:type_name -> istio.networking.v1alpha3.Percent - 27, // 54: istio.networking.v1alpha3.Headers.HeaderOperations.set:type_name -> istio.networking.v1alpha3.Headers.HeaderOperations.SetEntry - 28, // 55: istio.networking.v1alpha3.Headers.HeaderOperations.add:type_name -> istio.networking.v1alpha3.Headers.HeaderOperations.AddEntry - 19, // 56: istio.networking.v1alpha3.HTTPMatchRequest.HeadersEntry.value:type_name -> istio.networking.v1alpha3.StringMatch - 19, // 57: istio.networking.v1alpha3.HTTPMatchRequest.QueryParamsEntry.value:type_name -> istio.networking.v1alpha3.StringMatch - 19, // 58: istio.networking.v1alpha3.HTTPMatchRequest.WithoutHeadersEntry.value:type_name -> istio.networking.v1alpha3.StringMatch - 37, // 59: istio.networking.v1alpha3.HTTPFaultInjection.Delay.fixed_delay:type_name -> google.protobuf.Duration - 37, // 60: istio.networking.v1alpha3.HTTPFaultInjection.Delay.exponential_delay:type_name -> google.protobuf.Duration - 25, // 61: istio.networking.v1alpha3.HTTPFaultInjection.Delay.percentage:type_name -> istio.networking.v1alpha3.Percent - 25, // 62: istio.networking.v1alpha3.HTTPFaultInjection.Abort.percentage:type_name -> istio.networking.v1alpha3.Percent - 63, // [63:63] is the sub-list for method output_type - 63, // [63:63] is the sub-list for method input_type - 63, // [63:63] is the sub-list for extension type_name - 63, // [63:63] is the sub-list for extension extendee - 0, // [0:63] is the sub-list for field type_name + 16, // 39: istio.networking.v1alpha3.HTTPDirectResponse.body:type_name -> istio.networking.v1alpha3.HTTPBody + 18, // 40: istio.networking.v1alpha3.HTTPRewrite.uri_regex_rewrite:type_name -> istio.networking.v1alpha3.RegexRewrite + 37, // 41: istio.networking.v1alpha3.HTTPRetry.per_try_timeout:type_name -> google.protobuf.Duration + 39, // 42: istio.networking.v1alpha3.HTTPRetry.retry_remote_localities:type_name -> google.protobuf.BoolValue + 39, // 43: istio.networking.v1alpha3.HTTPRetry.retry_ignore_previous_hosts:type_name -> google.protobuf.BoolValue + 37, // 44: istio.networking.v1alpha3.HTTPRetry.backoff:type_name -> google.protobuf.Duration + 19, // 45: istio.networking.v1alpha3.CorsPolicy.allow_origins:type_name -> istio.networking.v1alpha3.StringMatch + 37, // 46: istio.networking.v1alpha3.CorsPolicy.max_age:type_name -> google.protobuf.Duration + 39, // 47: istio.networking.v1alpha3.CorsPolicy.allow_credentials:type_name -> google.protobuf.BoolValue + 1, // 48: istio.networking.v1alpha3.CorsPolicy.unmatched_preflights:type_name -> istio.networking.v1alpha3.CorsPolicy.UnmatchedPreflights + 35, // 49: istio.networking.v1alpha3.HTTPFaultInjection.delay:type_name -> istio.networking.v1alpha3.HTTPFaultInjection.Delay + 36, // 50: istio.networking.v1alpha3.HTTPFaultInjection.abort:type_name -> istio.networking.v1alpha3.HTTPFaultInjection.Abort + 3, // 51: istio.networking.v1alpha3.HTTPMirrorPolicy.destination:type_name -> istio.networking.v1alpha3.Destination + 25, // 52: istio.networking.v1alpha3.HTTPMirrorPolicy.percentage:type_name -> istio.networking.v1alpha3.Percent + 27, // 53: istio.networking.v1alpha3.Headers.HeaderOperations.set:type_name -> istio.networking.v1alpha3.Headers.HeaderOperations.SetEntry + 28, // 54: istio.networking.v1alpha3.Headers.HeaderOperations.add:type_name -> istio.networking.v1alpha3.Headers.HeaderOperations.AddEntry + 19, // 55: istio.networking.v1alpha3.HTTPMatchRequest.HeadersEntry.value:type_name -> istio.networking.v1alpha3.StringMatch + 19, // 56: istio.networking.v1alpha3.HTTPMatchRequest.QueryParamsEntry.value:type_name -> istio.networking.v1alpha3.StringMatch + 19, // 57: istio.networking.v1alpha3.HTTPMatchRequest.WithoutHeadersEntry.value:type_name -> istio.networking.v1alpha3.StringMatch + 37, // 58: istio.networking.v1alpha3.HTTPFaultInjection.Delay.fixed_delay:type_name -> google.protobuf.Duration + 37, // 59: istio.networking.v1alpha3.HTTPFaultInjection.Delay.exponential_delay:type_name -> google.protobuf.Duration + 25, // 60: istio.networking.v1alpha3.HTTPFaultInjection.Delay.percentage:type_name -> istio.networking.v1alpha3.Percent + 25, // 61: istio.networking.v1alpha3.HTTPFaultInjection.Abort.percentage:type_name -> istio.networking.v1alpha3.Percent + 62, // [62:62] is the sub-list for method output_type + 62, // [62:62] is the sub-list for method input_type + 62, // [62:62] is the sub-list for extension type_name + 62, // [62:62] is the sub-list for extension extendee + 0, // [0:62] is the sub-list for field type_name } func init() { file_networking_v1alpha3_virtual_service_proto_init() } @@ -3943,8 +3892,6 @@ func file_networking_v1alpha3_virtual_service_proto_init() { file_networking_v1alpha3_virtual_service_proto_msgTypes[12].OneofWrappers = []any{ (*HTTPRedirect_Port)(nil), (*HTTPRedirect_DerivePort)(nil), - (*HTTPRedirect_PrefixRewrite)(nil), - (*HTTPRedirect_UriRegexRewrite)(nil), } file_networking_v1alpha3_virtual_service_proto_msgTypes[14].OneofWrappers = []any{ (*HTTPBody_String_)(nil), diff --git a/networking/v1alpha3/virtual_service.proto b/networking/v1alpha3/virtual_service.proto index 700c0c2cff..6a90199725 100644 --- a/networking/v1alpha3/virtual_service.proto +++ b/networking/v1alpha3/virtual_service.proto @@ -1102,7 +1102,7 @@ message HTTPRedirect { // value. Note that the entire path will be replaced, irrespective of the // request URI being matched as an exact path or prefix. // - // Mutually exclusive with prefix_rewrite and uri_regex_rewrite. + // Mutually exclusive with prefix_rewrite. string uri = 1; // On a redirect, overwrite the Authority/Host portion of the URL with @@ -1132,29 +1132,16 @@ message HTTPRedirect { // response. The default response code is MOVED_PERMANENTLY (301). uint32 redirect_code = 3; - // Specifies how to rewrite the path on redirect. Exactly one of uri, - // prefix_rewrite, or uri_regex_rewrite may be set. - oneof path_rewrite_specifier { - // On a redirect, replace the matched prefix (or the entire path for exact - // matches) with this value. The route match must use a prefix match type. - // The matched prefix is stripped from the path and this value is prepended. - // - // Examples (route prefix match: /foo): - // - prefix_rewrite: /bar → /foo/baz becomes /bar/baz - // - prefix_rewrite: / → /foo/baz becomes //baz (use /foo/ match to get /baz) - // - // Mutually exclusive with uri and uri_regex_rewrite. - string prefix_rewrite = 7; - - // On a redirect, rewrite the path portion of the URI with the specified - // RE2 regex. Capture groups in the pattern may be referenced in the - // replacement string. - // - // Example: match "^/foo(/.*)$" with rewrite "\\1" rewrites /foo/bar to /bar. - // - // Mutually exclusive with uri and prefix_rewrite. - RegexRewrite uri_regex_rewrite = 8; - } + // On a redirect, replace the matched prefix with this value. The route match + // must use a prefix match type. The matched prefix is stripped from the path + // and this value is prepended. + // + // Examples (route prefix match: /foo): + // - prefix_rewrite: /bar → /foo/baz becomes /bar/baz + // - prefix_rewrite: / → /foo/baz becomes //baz (use /foo/ match to get /baz) + // + // Mutually exclusive with uri. + string prefix_rewrite = 7; } // HTTPDirectResponse can be used to send a fixed response to clients. From 959111bcb73c1f388138655bcf2d639797cc5716 Mon Sep 17 00:00:00 2001 From: Liam White Date: Tue, 26 May 2026 13:21:40 -0700 Subject: [PATCH 5/7] gen: remove uri_regex_rewrite from HTTPRedirect generated files --- kubernetes/customresourcedefinitions.gen.yaml | 150 +++++------------- networking/v1/virtual_service_alias.gen.go | 20 --- networking/v1alpha3/virtual_service.pb.html | 27 +--- .../v1beta1/virtual_service_alias.gen.go | 20 --- 4 files changed, 46 insertions(+), 171 deletions(-) diff --git a/kubernetes/customresourcedefinitions.gen.yaml b/kubernetes/customresourcedefinitions.gen.yaml index 08e49dde23..e1d0b590d8 100644 --- a/kubernetes/customresourcedefinitions.gen.yaml +++ b/kubernetes/customresourcedefinitions.gen.yaml @@ -11523,29 +11523,17 @@ spec: description: The name assigned to the route for debugging purposes. type: string redirect: - allOf: - - oneOf: - - not: - anyOf: - - required: - - port - - required: - - derivePort - - required: - - port - - required: - - derivePort - - oneOf: - - not: - anyOf: - - required: - - prefixRewrite - - required: - - uriRegexRewrite - - required: - - prefixRewrite - - required: - - uriRegexRewrite + oneOf: + - not: + anyOf: + - required: + - port + - required: + - derivePort + - required: + - port + - required: + - derivePort description: A HTTP rule can either return a direct_response, redirect or forward (default) traffic. properties: @@ -11569,8 +11557,8 @@ spec: minimum: 0 type: integer prefixRewrite: - description: On a redirect, replace the matched prefix (or - the entire path for exact matches) with this value. + description: On a redirect, replace the matched prefix with + this value. type: string redirectCode: description: On a redirect, Specifies the HTTP status code @@ -11586,18 +11574,6 @@ spec: description: On a redirect, overwrite the Path portion of the URL with this value. type: string - uriRegexRewrite: - description: On a redirect, rewrite the path portion of - the URI with the specified RE2 regex. - properties: - match: - description: '[RE2 style regex-based match](https://github.com/google/re2/wiki/Syntax).' - type: string - rewrite: - description: The string that should replace into matching - portions of original URI. - type: string - type: object type: object retries: description: Retry policy for HTTP requests. @@ -12603,29 +12579,17 @@ spec: description: The name assigned to the route for debugging purposes. type: string redirect: - allOf: - - oneOf: - - not: - anyOf: - - required: - - port - - required: - - derivePort - - required: - - port - - required: - - derivePort - - oneOf: - - not: - anyOf: - - required: - - prefixRewrite - - required: - - uriRegexRewrite - - required: - - prefixRewrite - - required: - - uriRegexRewrite + oneOf: + - not: + anyOf: + - required: + - port + - required: + - derivePort + - required: + - port + - required: + - derivePort description: A HTTP rule can either return a direct_response, redirect or forward (default) traffic. properties: @@ -12649,8 +12613,8 @@ spec: minimum: 0 type: integer prefixRewrite: - description: On a redirect, replace the matched prefix (or - the entire path for exact matches) with this value. + description: On a redirect, replace the matched prefix with + this value. type: string redirectCode: description: On a redirect, Specifies the HTTP status code @@ -12666,18 +12630,6 @@ spec: description: On a redirect, overwrite the Path portion of the URL with this value. type: string - uriRegexRewrite: - description: On a redirect, rewrite the path portion of - the URI with the specified RE2 regex. - properties: - match: - description: '[RE2 style regex-based match](https://github.com/google/re2/wiki/Syntax).' - type: string - rewrite: - description: The string that should replace into matching - portions of original URI. - type: string - type: object type: object retries: description: Retry policy for HTTP requests. @@ -13683,29 +13635,17 @@ spec: description: The name assigned to the route for debugging purposes. type: string redirect: - allOf: - - oneOf: - - not: - anyOf: - - required: - - port - - required: - - derivePort - - required: - - port - - required: - - derivePort - - oneOf: - - not: - anyOf: - - required: - - prefixRewrite - - required: - - uriRegexRewrite - - required: - - prefixRewrite - - required: - - uriRegexRewrite + oneOf: + - not: + anyOf: + - required: + - port + - required: + - derivePort + - required: + - port + - required: + - derivePort description: A HTTP rule can either return a direct_response, redirect or forward (default) traffic. properties: @@ -13729,8 +13669,8 @@ spec: minimum: 0 type: integer prefixRewrite: - description: On a redirect, replace the matched prefix (or - the entire path for exact matches) with this value. + description: On a redirect, replace the matched prefix with + this value. type: string redirectCode: description: On a redirect, Specifies the HTTP status code @@ -13746,18 +13686,6 @@ spec: description: On a redirect, overwrite the Path portion of the URL with this value. type: string - uriRegexRewrite: - description: On a redirect, rewrite the path portion of - the URI with the specified RE2 regex. - properties: - match: - description: '[RE2 style regex-based match](https://github.com/google/re2/wiki/Syntax).' - type: string - rewrite: - description: The string that should replace into matching - portions of original URI. - type: string - type: object type: object retries: description: Retry policy for HTTP requests. diff --git a/networking/v1/virtual_service_alias.gen.go b/networking/v1/virtual_service_alias.gen.go index 0151ff8ec6..b3af08a683 100644 --- a/networking/v1/virtual_service_alias.gen.go +++ b/networking/v1/virtual_service_alias.gen.go @@ -561,26 +561,6 @@ type HTTPRedirect_Port = v1alpha3.HTTPRedirect_Port // * FROM_REQUEST_PORT: automatically use the port of the request. type HTTPRedirect_DerivePort = v1alpha3.HTTPRedirect_DerivePort -// On a redirect, replace the matched prefix (or the entire path for exact -// matches) with this value. The route match must use a prefix match type. -// The matched prefix is stripped from the path and this value is prepended. -// -// Examples (route prefix match: /foo): -// - prefix_rewrite: /bar → /foo/baz becomes /bar/baz -// - prefix_rewrite: / → /foo/baz becomes //baz (use /foo/ match to get /baz) -// -// Mutually exclusive with uri and uri_regex_rewrite. -type HTTPRedirect_PrefixRewrite = v1alpha3.HTTPRedirect_PrefixRewrite - -// On a redirect, rewrite the path portion of the URI with the specified -// RE2 regex. Capture groups in the pattern may be referenced in the -// replacement string. -// -// Example: match "^/foo(/.*)$" with rewrite "\\1" rewrites /foo/bar to /bar. -// -// Mutually exclusive with uri and prefix_rewrite. -type HTTPRedirect_UriRegexRewrite = v1alpha3.HTTPRedirect_UriRegexRewrite - // HTTPDirectResponse can be used to send a fixed response to clients. // For example, the following rule returns a fixed 503 status with a body // to requests for /v1/getProductRatings API. diff --git a/networking/v1alpha3/virtual_service.pb.html b/networking/v1alpha3/virtual_service.pb.html index 4c245dac40..ae3223d69d 100644 --- a/networking/v1alpha3/virtual_service.pb.html +++ b/networking/v1alpha3/virtual_service.pb.html @@ -1544,7 +1544,7 @@

HTTPRedirect

On a redirect, overwrite the Path portion of the URL with this value. Note that the entire path will be replaced, irrespective of the request URI being matched as an exact path or prefix.

-

Mutually exclusive with prefix_rewrite and uri_regex_rewrite.

+

Mutually exclusive with prefix_rewrite.

@@ -1602,33 +1602,20 @@

HTTPRedirect

-
+ - - - - diff --git a/networking/v1beta1/virtual_service_alias.gen.go b/networking/v1beta1/virtual_service_alias.gen.go index eebe17ec8a..64157190c4 100644 --- a/networking/v1beta1/virtual_service_alias.gen.go +++ b/networking/v1beta1/virtual_service_alias.gen.go @@ -561,26 +561,6 @@ type HTTPRedirect_Port = v1alpha3.HTTPRedirect_Port // * FROM_REQUEST_PORT: automatically use the port of the request. type HTTPRedirect_DerivePort = v1alpha3.HTTPRedirect_DerivePort -// On a redirect, replace the matched prefix (or the entire path for exact -// matches) with this value. The route match must use a prefix match type. -// The matched prefix is stripped from the path and this value is prepended. -// -// Examples (route prefix match: /foo): -// - prefix_rewrite: /bar → /foo/baz becomes /bar/baz -// - prefix_rewrite: / → /foo/baz becomes //baz (use /foo/ match to get /baz) -// -// Mutually exclusive with uri and uri_regex_rewrite. -type HTTPRedirect_PrefixRewrite = v1alpha3.HTTPRedirect_PrefixRewrite - -// On a redirect, rewrite the path portion of the URI with the specified -// RE2 regex. Capture groups in the pattern may be referenced in the -// replacement string. -// -// Example: match "^/foo(/.*)$" with rewrite "\\1" rewrites /foo/bar to /bar. -// -// Mutually exclusive with uri and prefix_rewrite. -type HTTPRedirect_UriRegexRewrite = v1alpha3.HTTPRedirect_UriRegexRewrite - // HTTPDirectResponse can be used to send a fixed response to clients. // For example, the following rule returns a fixed 503 status with a body // to requests for /v1/getProductRatings API. From 66430797b0c68596e64b85eb427f445afcb41690 Mon Sep 17 00:00:00 2001 From: Liam White Date: Tue, 26 May 2026 13:24:38 -0700 Subject: [PATCH 6/7] gen: fix field ordering and line wrap in generated files --- kubernetes/customresourcedefinitions.gen.yaml | 12 ++++++------ networking/v1alpha3/virtual_service.pb.html | 6 +++--- 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/kubernetes/customresourcedefinitions.gen.yaml b/kubernetes/customresourcedefinitions.gen.yaml index e1d0b590d8..803a36b6d4 100644 --- a/kubernetes/customresourcedefinitions.gen.yaml +++ b/kubernetes/customresourcedefinitions.gen.yaml @@ -11523,6 +11523,8 @@ spec: description: The name assigned to the route for debugging purposes. type: string redirect: + description: A HTTP rule can either return a direct_response, + redirect or forward (default) traffic. oneOf: - not: anyOf: @@ -11534,8 +11536,6 @@ spec: - port - required: - derivePort - description: A HTTP rule can either return a direct_response, - redirect or forward (default) traffic. properties: authority: description: On a redirect, overwrite the Authority/Host @@ -12579,6 +12579,8 @@ spec: description: The name assigned to the route for debugging purposes. type: string redirect: + description: A HTTP rule can either return a direct_response, + redirect or forward (default) traffic. oneOf: - not: anyOf: @@ -12590,8 +12592,6 @@ spec: - port - required: - derivePort - description: A HTTP rule can either return a direct_response, - redirect or forward (default) traffic. properties: authority: description: On a redirect, overwrite the Authority/Host @@ -13635,6 +13635,8 @@ spec: description: The name assigned to the route for debugging purposes. type: string redirect: + description: A HTTP rule can either return a direct_response, + redirect or forward (default) traffic. oneOf: - not: anyOf: @@ -13646,8 +13648,6 @@ spec: - port - required: - derivePort - description: A HTTP rule can either return a direct_response, - redirect or forward (default) traffic. properties: authority: description: On a redirect, overwrite the Authority/Host diff --git a/networking/v1alpha3/virtual_service.pb.html b/networking/v1alpha3/virtual_service.pb.html index ae3223d69d..822483a32c 100644 --- a/networking/v1alpha3/virtual_service.pb.html +++ b/networking/v1alpha3/virtual_service.pb.html @@ -1607,9 +1607,9 @@

HTTPRedirect

string
-

On a redirect, replace the matched route prefix with this value. The route -match must use a prefix match type. The matched prefix is stripped from the -path and this value is prepended.

+

On a redirect, replace the matched prefix (or the entire path for exact +matches) with this value. The route match must use a prefix match type. +The matched prefix is stripped from the path and this value is prepended.

Examples (route prefix match: /foo):

    -
  • prefixRewrite: /bar → /foo/baz becomes /bar/baz
  • -
  • prefixRewrite: / → /foo/baz becomes //baz (use /foo/ match to get /baz)
  • +
  • prefix_rewrite: /bar → /foo/baz becomes /bar/baz
  • +
  • prefix_rewrite: / → /foo/baz becomes //baz (use /foo/ match to get /baz)
-

Mutually exclusive with uri and uriRegexRewrite.

+

Mutually exclusive with uri and uri_regex_rewrite.

-
string (oneof)
+
string
-

On a redirect, replace the matched prefix (or the entire path for exact -matches) with this value. The route match must use a prefix match type. -The matched prefix is stripped from the path and this value is prepended.

+

On a redirect, replace the matched prefix with this value. The route +match must use a prefix match type. The matched prefix is stripped from +the path and this value is prepended.

Examples (route prefix match: /foo):

  • prefix_rewrite: /bar → /foo/baz becomes /bar/baz
  • prefix_rewrite: / → /foo/baz becomes //baz (use /foo/ match to get /baz)
-

Mutually exclusive with uri and uri_regex_rewrite.

- -
-

On a redirect, rewrite the path portion of the URI with the specified -RE2 regex. Capture groups in the pattern may be referenced in the -replacement string.

-

Example: match “^/foo(/.*)$” with rewrite “\1” rewrites /foo/bar to /bar.

-

Mutually exclusive with uri and prefix_rewrite.

+

Mutually exclusive with uri.

-

On a redirect, replace the matched prefix with this value. The route -match must use a prefix match type. The matched prefix is stripped from -the path and this value is prepended.

+

On a redirect, replace the matched prefix with this value. The route match +must use a prefix match type. The matched prefix is stripped from the path +and this value is prepended.

Examples (route prefix match: /foo):

  • prefix_rewrite: /bar → /foo/baz becomes /bar/baz
  • From 15299541b8c6b46de638116a433e49081b13c23f Mon Sep 17 00:00:00 2001 From: Liam White Date: Tue, 26 May 2026 13:32:51 -0700 Subject: [PATCH 7/7] releasenotes: update note to reflect prefix_rewrite only --- releasenotes/notes/redirect-prefix-rewrite.yaml | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/releasenotes/notes/redirect-prefix-rewrite.yaml b/releasenotes/notes/redirect-prefix-rewrite.yaml index 78ee66577d..19c79e642b 100644 --- a/releasenotes/notes/redirect-prefix-rewrite.yaml +++ b/releasenotes/notes/redirect-prefix-rewrite.yaml @@ -8,7 +8,6 @@ issue: releaseNotes: - | - **Added** `prefix_rewrite` and `uri_regex_rewrite` fields to `HTTPRedirect`, allowing redirects - that preserve the path suffix. `prefix_rewrite` replaces only the matched route prefix (e.g. - `example.com/foo/bar` → `foo.example.com/bar`); `uri_regex_rewrite` applies an RE2 regex - substitution. Both are mutually exclusive with the existing `uri` field. + **Added** `prefix_rewrite` field to `HTTPRedirect`, allowing redirects that preserve the path + suffix. The matched route prefix is stripped and replaced with the specified value (e.g. + `example.com/foo/bar` → `foo.example.com/bar`). Mutually exclusive with the existing `uri` field.