http-client
http-client copied to clipboard
IsahcClient created without Config ignores the timeout setting.
IsahcClient::new()
creates a client with a timeout set to 60 seconds. However, this client does not actually return a timeout error after 60 seconds. IsahcClient created with Config and try_into does not have this problem and returns a timeout error after 60 seconds.
Here are some additional explanations.
- There is a concern related to this IsahcClient timeout issue. It is possible that settings other than timeout are also being ignored. Other clients may also have this issue.
- I noticed this problem while using surf. The timeout behavior was different for the two below.
let client: Client = Config::new()
.try_into()
.unwrap();
client.get("...").send().await;
surf::get("...").send().await;
- Here is the code I used to check the behavior. It takes more than 60 seconds to run. Depending on the environment, it may not work as expected.
use async_std::task;
use futures::prelude::*;
use http_client::{isahc, Config, HttpClient};
use std::time::Duration;
#[async_std::main]
async fn main() {
let mut tasks = vec![];
tasks.push(task::spawn(async {
let client: isahc::IsahcClient = Config::new()
.try_into()
.unwrap();
assert_eq!(client.config().timeout, Some(Duration::from_secs(60)));
run_test(client, "isahc: created with config").await;
}));
tasks.push(task::spawn(async {
let client = isahc::IsahcClient::new();
assert_eq!(client.config().timeout, Some(Duration::from_secs(60)));
run_test(client, "isahc: created by new()").await;
}));
println!("start tasks");
future::join_all(tasks).await;
}
async fn run_test(client: impl HttpClient, process_name: &str) {
let timeout = client.config().timeout.unwrap();
let sleep_duration = timeout + Duration::from_secs(1);
let result = communicate(client, sleep_duration).await;
let timeout_secs = timeout.as_secs();
let sleep_secs = sleep_duration.as_secs();
println!(
"{process_name}: config.timeout={timeout_secs} sleep={sleep_secs} result={:?}",
result
);
}
// Make a request to the server. Then read the body after the specified time has elapsed. Created to cause a timeout.
// If communication is successful, return Ok. Otherwise (including a timeout), return Err.
async fn communicate(client: impl HttpClient, sleep_duration: Duration) -> Result<(), std::io::Error> {
// If the body is to be read internally to the end, the size must be increased. Otherwise, it will not time out.
const BODY_BYTES: usize = 80 * 1024;
let url = format!("http://httpbin.org/bytes/{BODY_BYTES}");
let url = http_types::Url::parse(&url).unwrap();
let req = http_types::Request::get(url);
let mut res = client.send(req).await.unwrap();
let mut body = res.take_body().into_reader();
task::sleep(sleep_duration).await;
let mut total = vec![];
let read_bytes = body.read_to_end(&mut total).await?;
assert_eq!(read_bytes, BODY_BYTES);
Ok(())
}
isahc: created with config: config.timeout=60 sleep=61 result=Err(Kind(TimedOut))
isahc: created by new(): config.timeout=60 sleep=61 result=Ok(())