@@ -15,7 +15,10 @@ use volo::{client::Apply, context::Context};
1515use crate :: {
1616 client:: { Target , target:: RemoteHost , utils:: is_default_port} ,
1717 context:: ClientContext ,
18- error:: { ClientError , client:: request_error} ,
18+ error:: {
19+ ClientError ,
20+ client:: { Result , request_error} ,
21+ } ,
1922 request:: Request ,
2023} ;
2124
@@ -132,34 +135,38 @@ pub struct HttpProxyService<S> {
132135}
133136
134137impl < S > HttpProxyService < S > {
135- fn update_req < B > ( & self , cx : & mut ClientContext , req : & mut Request < B > ) {
138+ fn update_req < B > ( & self , cx : & mut ClientContext , req : & mut Request < B > ) -> Option < Target > {
136139 let Some ( target) = & self . target else {
137- return ;
140+ return None ;
138141 } ;
142+
143+ // A configured proxy is a routing requirement. Unsupported requests must not silently
144+ // fall back to a direct connection.
139145 if req. version ( ) != Version :: HTTP_11 {
140146 tracing:: info!( "[Volo-HTTP] HttpProxy only works for HTTP/1.1" ) ;
141- return ;
147+ return None ;
142148 }
143149 if let Some ( scheme) = cx. target ( ) . scheme ( ) {
144150 if scheme != & Scheme :: HTTP {
145151 tracing:: info!( "[Volo-HTTP] HttpProxy only supports HTTP protocol" ) ;
146- return ;
152+ return None ;
147153 }
148154 }
149155
150- // Generate authority by old target, and then update request
156+ // Generate authority from the logical upstream target, then rewrite the HTTP/1.1
157+ // request-target to absolute-form for the proxy.
151158 let Some ( authority) = gen_authority ( cx. target ( ) ) else {
152159 tracing:: warn!(
153160 "[Volo-HTTP] HttpProxy: failed to gen authority by {:?}" ,
154161 cx. target( )
155162 ) ;
156- return ;
163+ return None ;
157164 } ;
158165 let authority = match Authority :: from_maybe_shared ( Bytes :: from ( authority) ) {
159166 Ok ( authority) => authority,
160167 Err ( e) => {
161168 tracing:: warn!( "[Volo-HTTP] HttpProxy: failed to parse authority: {e}" ) ;
162- return ;
169+ return None ;
163170 }
164171 } ;
165172 let mut parts = req. uri ( ) . to_owned ( ) . into_parts ( ) ;
@@ -174,19 +181,20 @@ impl<S> HttpProxyService<S> {
174181 Ok ( uri) => uri,
175182 Err ( e) => {
176183 tracing:: warn!( "[Volo-HTTP] HttpProxy: failed to build uri: {e}" ) ;
177- return ;
184+ return None ;
178185 }
179186 } ;
180187 * req. uri_mut ( ) = uri;
181188
182- // Clear callee and update proxy target to it
183- // Note: we must apply target after updating request because `target.apply(cx)` will update
184- // self to `cx.target`
189+ // Only the transport target becomes the proxy. HttpProxy::call owns restoring the logical
190+ // upstream after the inner call returns.
185191 cx. rpc_info_mut ( ) . callee_mut ( ) . clear ( ) ;
186- target
192+ let old_target = target
187193 . to_owned ( )
188- . apply ( cx)
194+ . apply_and_replace ( cx)
189195 . expect ( "infallible: failed to parse target in HttpProxy" ) ;
196+
197+ Some ( old_target)
190198 }
191199}
192200
@@ -227,6 +235,11 @@ fn gen_authority(target: &Target) -> Option<String> {
227235 Some ( host)
228236}
229237
238+ fn restore_target ( cx : & mut ClientContext , target : Target ) -> Result < ( ) > {
239+ cx. rpc_info_mut ( ) . callee_mut ( ) . clear ( ) ;
240+ target. apply ( cx)
241+ }
242+
230243impl < B , S > Service < ClientContext , Request < B > > for HttpProxyService < S >
231244where
232245 B : Send ,
@@ -240,8 +253,17 @@ where
240253 cx : & mut ClientContext ,
241254 mut req : Request < B > ,
242255 ) -> Result < Self :: Response , Self :: Error > {
243- self . update_req ( cx, & mut req) ;
244- match self . inner . call ( cx, req) . await {
256+ let old_target = self . update_req ( cx, & mut req) ;
257+ let result = self . inner . call ( cx, req) . await ;
258+
259+ // HttpProxy only borrows cx.target() as a transport target. Restore the logical upstream
260+ // before returning to FollowRedirect or any other outer layer. Do this for both success and
261+ // error responses.
262+ if let Some ( target) = old_target {
263+ restore_target ( cx, target) ?;
264+ } ;
265+
266+ match result {
245267 Ok ( resp) => Ok ( resp) ,
246268 Err ( e) => {
247269 if let Some ( target) = & self . target {
0 commit comments