@@ -38,7 +38,6 @@ use std::{
3838 str:: FromStr ,
3939 time:: Duration ,
4040} ;
41-
4241#[ derive( Debug , Clone , Deserialize , Serialize , PartialEq , Eq ) ]
4342#[ serde( rename_all = "snake_case" ) ]
4443pub enum Action {
@@ -132,6 +131,47 @@ impl PathRewriteSpecifier {
132131 }
133132}
134133
134+ impl AuthorityRewriteSpecifier {
135+ /// Applies authority rewrite based on the specifier type
136+ pub fn apply (
137+ & self ,
138+ uri : & http:: Uri ,
139+ headers : & http:: HeaderMap ,
140+ upstream_authority : & Authority ,
141+ ) -> Option < Authority > {
142+ match self {
143+ AuthorityRewriteSpecifier :: Authority ( authority) => Some ( authority. clone ( ) ) ,
144+
145+ AuthorityRewriteSpecifier :: Header ( header_name) => {
146+ let Some ( header_value) = headers. get ( header_name. as_str ( ) ) else {
147+ return None ;
148+ } ;
149+ let Ok ( header_str) = header_value. to_str ( ) else {
150+ return None ;
151+ } ;
152+ Authority :: from_str ( header_str) . ok ( )
153+ } ,
154+
155+ AuthorityRewriteSpecifier :: Regex ( regex) => {
156+ let current_authority = uri
157+ . authority ( )
158+ . map ( Authority :: as_str)
159+ . or_else ( || headers. get ( http:: header:: HOST ) . and_then ( |h| h. to_str ( ) . ok ( ) ) )
160+ . unwrap_or_default ( ) ;
161+
162+ let replacement = regex. pattern . replace_all ( current_authority, regex. substitution . as_str ( ) ) ;
163+ if let std:: borrow:: Cow :: Borrowed ( _) = replacement {
164+ None
165+ } else {
166+ Authority :: from_str ( & replacement) . ok ( )
167+ }
168+ } ,
169+
170+ AuthorityRewriteSpecifier :: AutoHostRewrite => Some ( upstream_authority. clone ( ) ) ,
171+ }
172+ }
173+ }
174+
135175#[ derive( Debug , Clone , Deserialize , Serialize , PartialEq , Eq ) ]
136176pub struct RedirectAction {
137177 pub response_code : RedirectResponseCode ,
@@ -649,6 +689,87 @@ mod tests {
649689 let result = route_match. match_request ( & req) ;
650690 assert ! ( !result. matched( ) ) ;
651691 }
692+
693+ #[ test]
694+ fn test_authority_rewrite_auto_host_rewrite ( ) {
695+ let authority_rewrite = AuthorityRewriteSpecifier :: AutoHostRewrite ;
696+ let upstream_authority = Authority :: from_str ( "upstream.example.com:8080" ) . unwrap ( ) ;
697+ let uri = "http://original.example.com/path" . parse :: < http:: Uri > ( ) . unwrap ( ) ;
698+ let mut headers = http:: HeaderMap :: new ( ) ;
699+ headers. insert ( "host" , "original.example.com" . parse ( ) . unwrap ( ) ) ;
700+
701+ let result = authority_rewrite. apply ( & uri, & headers, & upstream_authority) ;
702+ assert_eq ! ( result, Some ( upstream_authority) ) ;
703+ }
704+
705+ #[ test]
706+ fn test_authority_rewrite_specific_authority ( ) {
707+ let target_authority = Authority :: from_str ( "target.example.com:9090" ) . unwrap ( ) ;
708+ let authority_rewrite = AuthorityRewriteSpecifier :: Authority ( target_authority. clone ( ) ) ;
709+ let upstream_authority = Authority :: from_str ( "upstream.example.com:8080" ) . unwrap ( ) ;
710+ let uri = "http://original.example.com/path" . parse :: < http:: Uri > ( ) . unwrap ( ) ;
711+ let mut headers = http:: HeaderMap :: new ( ) ;
712+ headers. insert ( "host" , "original.example.com" . parse ( ) . unwrap ( ) ) ;
713+
714+ let result = authority_rewrite. apply ( & uri, & headers, & upstream_authority) ;
715+ assert_eq ! ( result, Some ( target_authority) ) ;
716+ }
717+
718+ #[ test]
719+ fn test_authority_rewrite_header ( ) {
720+ let authority_rewrite = AuthorityRewriteSpecifier :: Header ( "x-target-host" . into ( ) ) ;
721+ let upstream_authority = Authority :: from_str ( "upstream.example.com:8080" ) . unwrap ( ) ;
722+ let uri = "http://original.example.com/path" . parse :: < http:: Uri > ( ) . unwrap ( ) ;
723+ let mut headers = http:: HeaderMap :: new ( ) ;
724+ headers. insert ( "host" , "original.example.com" . parse ( ) . unwrap ( ) ) ;
725+ headers. insert ( "x-target-host" , "header.example.com:7070" . parse ( ) . unwrap ( ) ) ;
726+
727+ let result = authority_rewrite. apply ( & uri, & headers, & upstream_authority) ;
728+ assert_eq ! ( result, Some ( Authority :: from_str( "header.example.com:7070" ) . unwrap( ) ) ) ;
729+ }
730+
731+ #[ test]
732+ fn test_authority_rewrite_header_missing ( ) {
733+ let authority_rewrite = AuthorityRewriteSpecifier :: Header ( "x-missing-header" . into ( ) ) ;
734+ let upstream_authority = Authority :: from_str ( "upstream.example.com:8080" ) . unwrap ( ) ;
735+ let uri = "http://original.example.com/path" . parse :: < http:: Uri > ( ) . unwrap ( ) ;
736+ let mut headers = http:: HeaderMap :: new ( ) ;
737+ headers. insert ( "host" , "original.example.com" . parse ( ) . unwrap ( ) ) ;
738+
739+ let result = authority_rewrite. apply ( & uri, & headers, & upstream_authority) ;
740+ assert_eq ! ( result, None ) ;
741+ }
742+
743+ #[ test]
744+ fn test_authority_rewrite_regex ( ) {
745+ let regex = RegexMatchAndSubstitute {
746+ pattern : Regex :: new ( r"^([^.]+)\.original\.com$" ) . unwrap ( ) ,
747+ substitution : "${1}.rewritten.com" . into ( ) ,
748+ } ;
749+ let authority_rewrite = AuthorityRewriteSpecifier :: Regex ( regex) ;
750+ let upstream_authority = Authority :: from_str ( "upstream.example.com:8080" ) . unwrap ( ) ;
751+ let uri = "http://api.original.com/path" . parse :: < http:: Uri > ( ) . unwrap ( ) ;
752+ let mut headers = http:: HeaderMap :: new ( ) ;
753+ headers. insert ( "host" , "api.original.com" . parse ( ) . unwrap ( ) ) ;
754+
755+ let result = authority_rewrite. apply ( & uri, & headers, & upstream_authority) ;
756+ assert_eq ! ( result, Some ( Authority :: from_str( "api.rewritten.com" ) . unwrap( ) ) ) ;
757+ }
758+
759+ #[ test]
760+ fn test_authority_rewrite_regex_no_host_header ( ) {
761+ let regex = RegexMatchAndSubstitute {
762+ pattern : Regex :: new ( r"^([^.]+)\.original\.com$" ) . unwrap ( ) ,
763+ substitution : "${1}.rewritten.com" . into ( ) ,
764+ } ;
765+ let authority_rewrite = AuthorityRewriteSpecifier :: Regex ( regex) ;
766+ let upstream_authority = Authority :: from_str ( "upstream.example.com:8080" ) . unwrap ( ) ;
767+ let uri = "/path" . parse :: < http:: Uri > ( ) . unwrap ( ) ;
768+ let headers = http:: HeaderMap :: new ( ) ;
769+
770+ let result = authority_rewrite. apply ( & uri, & headers, & upstream_authority) ;
771+ assert_eq ! ( result, None ) ;
772+ }
652773}
653774
654775#[ cfg( feature = "envoy-conversions" ) ]
0 commit comments