@@ -21,7 +21,7 @@ use serde::{Deserialize, Serialize};
2121use super :: super :: is_default;
2222
2323/// Set Filter State HTTP filter configuration
24- ///
24+ ///
2525/// This filter dynamically sets filter state objects based on request data.
2626/// Filter state can be used for routing decisions, metadata propagation,
2727/// and internal connection handling.
@@ -36,33 +36,33 @@ pub struct SetFilterState {
3636#[ derive( Debug , Clone , Deserialize , Serialize , PartialEq , Eq ) ]
3737pub struct FilterStateValue {
3838 /// Filter state object key (required)
39- ///
39+ ///
4040 /// Examples:
4141 /// - "io.istio.connect_authority" (Istio HBONE)
4242 /// - "envoy.filters.listener.original_dst.local_ip"
4343 /// - "envoy.tcp_proxy.cluster"
4444 pub object_key : CompactString ,
45-
45+
4646 /// Optional factory key for object creation
4747 /// If not specified, object_key is used for factory lookup
4848 #[ serde( skip_serializing_if = "Option::is_none" , default ) ]
4949 pub factory_key : Option < CompactString > ,
50-
50+
5151 /// Format string to generate the value
5252 /// Supports Envoy substitution format strings like:
5353 /// - %REQ(:authority)% - Request header
5454 /// - %DOWNSTREAM_REMOTE_ADDRESS% - Client IP
5555 /// - %UPSTREAM_HOST% - Selected upstream
5656 pub format_string : FormatString ,
57-
57+
5858 /// Make this value read-only (cannot be overridden by other filters)
5959 #[ serde( skip_serializing_if = "std::ops::Not::not" , default ) ]
6060 pub read_only : bool ,
61-
61+
6262 /// Share with upstream internal connections
6363 #[ serde( skip_serializing_if = "is_default" , default ) ]
6464 pub shared_with_upstream : SharedWithUpstream ,
65-
65+
6666 /// Skip setting the value if it evaluates to empty string
6767 #[ serde( skip_serializing_if = "std::ops::Not::not" , default ) ]
6868 pub skip_if_empty : bool ,
@@ -88,7 +88,7 @@ pub enum FormatString {
8888 /// Plain text format string with command operators
8989 /// Example: "%REQ(:authority)%"
9090 Text ( CompactString ) ,
91-
91+
9292 /// Structured format (JSON, etc.) - future extension
9393 Structured {
9494 format : CompactString ,
@@ -101,60 +101,53 @@ pub enum FormatString {
101101mod envoy_conversions {
102102 use super :: * ;
103103 use crate :: config:: common:: * ;
104- use orion_data_plane_api:: envoy_data_plane_api:: {
105- envoy:: {
106- config:: core:: v3:: SubstitutionFormatString as EnvoySubstitutionFormatString ,
107- extensions:: filters:: {
108- common:: set_filter_state:: v3:: {
109- FilterStateValue as EnvoyFilterStateValue ,
110- filter_state_value:: {
111- Key as EnvoyKey ,
112- Value as EnvoyValue ,
113- SharedWithUpstream as EnvoySharedWithUpstream
114- } ,
104+ use orion_data_plane_api:: envoy_data_plane_api:: envoy:: {
105+ config:: core:: v3:: SubstitutionFormatString as EnvoySubstitutionFormatString ,
106+ extensions:: filters:: {
107+ common:: set_filter_state:: v3:: {
108+ filter_state_value:: {
109+ Key as EnvoyKey , SharedWithUpstream as EnvoySharedWithUpstream , Value as EnvoyValue ,
115110 } ,
116- http :: set_filter_state :: v3 :: Config as EnvoySetFilterStateConfig ,
111+ FilterStateValue as EnvoyFilterStateValue ,
117112 } ,
113+ http:: set_filter_state:: v3:: Config as EnvoySetFilterStateConfig ,
118114 } ,
119115 } ;
120-
116+
121117 impl TryFrom < EnvoySetFilterStateConfig > for SetFilterState {
122118 type Error = GenericError ;
123-
119+
124120 fn try_from ( envoy : EnvoySetFilterStateConfig ) -> Result < Self , Self :: Error > {
125- let on_request_headers = envoy. on_request_headers
121+ let on_request_headers = envoy
122+ . on_request_headers
126123 . into_iter ( )
127124 . map ( FilterStateValue :: try_from)
128125 . collect :: < Result < Vec < _ > , _ > > ( )
129126 . with_node ( "on_request_headers" ) ?;
130-
127+
131128 Ok ( Self { on_request_headers } )
132129 }
133130 }
134-
131+
135132 impl TryFrom < EnvoyFilterStateValue > for FilterStateValue {
136133 type Error = GenericError ;
137-
134+
138135 fn try_from ( envoy : EnvoyFilterStateValue ) -> Result < Self , Self :: Error > {
139136 let object_key = match envoy. key {
140137 Some ( EnvoyKey :: ObjectKey ( key) ) => CompactString :: from ( key) ,
141138 None => return Err ( GenericError :: from_msg ( "missing object_key in FilterStateValue" ) ) ,
142139 } ;
143-
144- let factory_key = if envoy. factory_key . is_empty ( ) {
145- None
146- } else {
147- Some ( envoy. factory_key . into ( ) )
148- } ;
149-
140+
141+ let factory_key = ( !envoy. factory_key . is_empty ( ) ) . then ( || envoy. factory_key . into ( ) ) ;
142+
150143 let format_string = match envoy. value {
151144 Some ( EnvoyValue :: FormatString ( fs) ) => FormatString :: try_from ( fs) . with_node ( "format_string" ) ?,
152145 None => return Err ( GenericError :: from_msg ( "missing format_string in FilterStateValue" ) ) ,
153146 } ;
154-
155- let shared_with_upstream = SharedWithUpstream :: try_from ( envoy . shared_with_upstream )
156- . with_node ( "shared_with_upstream" ) ?;
157-
147+
148+ let shared_with_upstream =
149+ SharedWithUpstream :: try_from ( envoy . shared_with_upstream ) . with_node ( "shared_with_upstream" ) ?;
150+
158151 Ok ( Self {
159152 object_key,
160153 factory_key,
@@ -165,34 +158,31 @@ mod envoy_conversions {
165158 } )
166159 }
167160 }
168-
161+
169162 impl TryFrom < EnvoySubstitutionFormatString > for FormatString {
170163 type Error = GenericError ;
171-
164+
172165 fn try_from ( envoy : EnvoySubstitutionFormatString ) -> Result < Self , Self :: Error > {
173166 use orion_data_plane_api:: envoy_data_plane_api:: envoy:: config:: core:: v3:: {
174- substitution_format_string:: Format ,
175- data_source:: Specifier ,
167+ data_source:: Specifier , substitution_format_string:: Format ,
176168 } ;
177-
169+
178170 match envoy. format {
179171 Some ( Format :: TextFormat ( text) ) => Ok ( FormatString :: Text ( text. into ( ) ) ) ,
180- Some ( Format :: TextFormatSource ( source) ) => {
181- match source. specifier {
182- Some ( Specifier :: InlineString ( s) ) => Ok ( FormatString :: Text ( s. into ( ) ) ) ,
183- Some ( Specifier :: InlineBytes ( b) ) => {
184- let s = String :: from_utf8 ( b)
185- . map_err ( |e| GenericError :: from_msg ( format ! ( "Invalid UTF-8 in format string: {}" , e) ) ) ?;
186- Ok ( FormatString :: Text ( s. into ( ) ) )
187- } ,
188- Some ( Specifier :: Filename ( _) ) => {
189- Err ( GenericError :: unsupported_variant ( "filename format strings not supported" ) )
190- } ,
191- Some ( Specifier :: EnvironmentVariable ( _) ) => {
192- Err ( GenericError :: unsupported_variant ( "environment variable format strings not supported" ) )
193- } ,
194- None => Err ( GenericError :: from_msg ( "missing format string specifier" ) ) ,
195- }
172+ Some ( Format :: TextFormatSource ( source) ) => match source. specifier {
173+ Some ( Specifier :: InlineString ( s) ) => Ok ( FormatString :: Text ( s. into ( ) ) ) ,
174+ Some ( Specifier :: InlineBytes ( b) ) => {
175+ let s = String :: from_utf8 ( b)
176+ . map_err ( |e| GenericError :: from_msg ( format ! ( "Invalid UTF-8 in format string: {}" , e) ) ) ?;
177+ Ok ( FormatString :: Text ( s. into ( ) ) )
178+ } ,
179+ Some ( Specifier :: Filename ( _) ) => {
180+ Err ( GenericError :: unsupported_variant ( "filename format strings not supported" ) )
181+ } ,
182+ Some ( Specifier :: EnvironmentVariable ( _) ) => {
183+ Err ( GenericError :: unsupported_variant ( "environment variable format strings not supported" ) )
184+ } ,
185+ None => Err ( GenericError :: from_msg ( "missing format string specifier" ) ) ,
196186 } ,
197187 Some ( Format :: JsonFormat ( _) ) => {
198188 // JSON format not yet supported - would need structured logging
@@ -204,7 +194,7 @@ mod envoy_conversions {
204194 }
205195 impl TryFrom < i32 > for SharedWithUpstream {
206196 type Error = GenericError ;
207-
197+
208198 fn try_from ( value : i32 ) -> Result < Self , Self :: Error > {
209199 match EnvoySharedWithUpstream :: try_from ( value) {
210200 Ok ( EnvoySharedWithUpstream :: None ) => Ok ( Self :: None ) ,
0 commit comments