@@ -16,11 +16,11 @@ use http::{HeaderValue, Method as HttpMethod, Uri, Version as HttpVersion, heade
1616use hyper:: {
1717 Request , Response ,
1818 body:: { self , Body } ,
19- client:: conn:: { http1, http2} ,
19+ client:: conn:: { TrySendError , http1, http2} ,
2020 http:: uri:: Scheme ,
2121 rt:: { Sleep , Timer } ,
2222} ;
23- use log:: { error, trace} ;
23+ use log:: { debug , error, trace} ;
2424use lru_time_cache:: LruCache ;
2525use pin_project:: pin_project;
2626use shadowsocks:: relay:: Address ;
@@ -34,7 +34,7 @@ use super::{
3434 utils:: { check_keep_alive, connect_host, host_addr} ,
3535} ;
3636
37- const CONNECTION_EXPIRE_DURATION : Duration = Duration :: from_secs ( 5 ) ;
37+ const CONNECTION_EXPIRE_DURATION : Duration = Duration :: from_secs ( 20 ) ;
3838
3939/// HTTPClient API request errors
4040#[ derive( thiserror:: Error , Debug ) ]
@@ -53,6 +53,15 @@ pub enum HttpClientError {
5353 InvalidHeaderValue ( #[ from] InvalidHeaderValue ) ,
5454}
5555
56+ #[ derive( thiserror:: Error , Debug ) ]
57+ enum SendRequestError < B > {
58+ #[ error( "{0}" ) ]
59+ Http ( #[ from] http:: Error ) ,
60+
61+ #[ error( "{0}" ) ]
62+ TrySend ( #[ from] TrySendError < Request < B > > ) ,
63+ }
64+
5665#[ derive( Clone , Debug ) ]
5766pub struct TokioTimer ;
5867
@@ -167,14 +176,40 @@ where
167176 headers. insert ( "Host" , host_value) ;
168177 }
169178 }
170- let req = Request :: from_parts ( req_parts, req_body) ;
179+ let mut req = Request :: from_parts ( req_parts, req_body) ;
171180
172181 // 1. Check if there is an available client
173- //
174- // FIXME: If the cached connection is closed unexpectedly, this request will fail immediately.
175182 if let Some ( c) = self . get_cached_connection ( & host) . await {
176183 trace ! ( "HTTP client for host: {} taken from cache" , host) ;
177- return self . send_request_conn ( host, c, req) . await ;
184+ match self . send_request_conn ( host. clone ( ) , c, req) . await {
185+ Ok ( response) => return Ok ( response) ,
186+ Err ( SendRequestError :: TrySend ( mut err) ) => {
187+ if let Some ( inner_req) = err. take_message ( ) {
188+ req = inner_req;
189+
190+ // If TrySendError, the connection is probably broken, we should make a new connection
191+ debug ! (
192+ "failed to send request via cached connection to host: {}, error: {}. retry with a new connection" ,
193+ host,
194+ err. error( )
195+ ) ;
196+ } else {
197+ error ! (
198+ "failed to send request via cached connection to host: {}, error: {}. no request to retry" ,
199+ host,
200+ err. error( )
201+ ) ;
202+ return Err ( err. into_error ( ) . into ( ) ) ;
203+ }
204+ }
205+ Err ( SendRequestError :: Http ( err) ) => {
206+ error ! (
207+ "failed to send request via cached connection to host: {}, error: {}" ,
208+ host, err
209+ ) ;
210+ return Err ( err. into ( ) ) ;
211+ }
212+ }
178213 }
179214
180215 // 2. If no. Make a new connection
@@ -196,7 +231,11 @@ where
196231 }
197232 } ;
198233
199- self . send_request_conn ( host, c, req) . await
234+ match self . send_request_conn ( host, c, req) . await {
235+ Ok ( response) => Ok ( response) ,
236+ Err ( SendRequestError :: TrySend ( err) ) => Err ( err. into_error ( ) . into ( ) ) ,
237+ Err ( SendRequestError :: Http ( err) ) => Err ( err. into ( ) ) ,
238+ }
200239 }
201240
202241 async fn get_cached_connection ( & self , host : & Address ) -> Option < HttpConnection < B > > {
@@ -220,7 +259,7 @@ where
220259 host : Address ,
221260 mut c : HttpConnection < B > ,
222261 req : Request < B > ,
223- ) -> Result < Response < body:: Incoming > , HttpClientError > {
262+ ) -> Result < Response < body:: Incoming > , SendRequestError < B > > {
224263 trace ! ( "HTTP making request to host: {}, request: {:?}" , host, req) ;
225264 let response = c. send_request ( req) . await ?;
226265 trace ! ( "HTTP received response from host: {}, response: {:?}" , host, response) ;
@@ -357,7 +396,7 @@ where
357396 }
358397
359398 #[ inline]
360- pub async fn send_request ( & mut self , mut req : Request < B > ) -> Result < Response < body:: Incoming > , HttpClientError > {
399+ pub async fn send_request ( & mut self , mut req : Request < B > ) -> Result < Response < body:: Incoming > , SendRequestError < B > > {
361400 match self {
362401 Self :: Http1 ( r) => {
363402 if !matches ! (
@@ -388,7 +427,7 @@ where
388427 * ( req. uri_mut ( ) ) = builder. build ( ) ?;
389428 }
390429
391- r. send_request ( req) . await . map_err ( Into :: into)
430+ r. try_send_request ( req) . await . map_err ( Into :: into)
392431 }
393432 Self :: Http2 ( r) => {
394433 if !matches ! ( req. version( ) , HttpVersion :: HTTP_2 ) {
@@ -397,7 +436,7 @@ where
397436 * req. version_mut ( ) = HttpVersion :: HTTP_2 ;
398437 }
399438
400- r. send_request ( req) . await . map_err ( Into :: into)
439+ r. try_send_request ( req) . await . map_err ( Into :: into)
401440 }
402441 }
403442 }
0 commit comments