Skip to content

Commit 0321037

Browse files
committed
feat(shadowsocks-service): HTTP client auto retry (#2026)
1 parent 8398611 commit 0321037

File tree

1 file changed

+51
-12
lines changed

1 file changed

+51
-12
lines changed

crates/shadowsocks-service/src/local/http/http_client.rs

Lines changed: 51 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -16,11 +16,11 @@ use http::{HeaderValue, Method as HttpMethod, Uri, Version as HttpVersion, heade
1616
use 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};
2424
use lru_time_cache::LruCache;
2525
use pin_project::pin_project;
2626
use 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)]
5766
pub 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

Comments
 (0)