From 4afea0318aa179d9289bcd33a789191552446289 Mon Sep 17 00:00:00 2001 From: jprochazk Date: Thu, 4 Dec 2025 18:16:16 +0100 Subject: [PATCH 1/2] Support configurable connection timeout --- ehttp/src/lib.rs | 2 ++ ehttp/src/native.rs | 5 +++++ ehttp/src/types.rs | 13 +++++++++++++ ehttp/src/web.rs | 1 + 4 files changed, 21 insertions(+) diff --git a/ehttp/src/lib.rs b/ehttp/src/lib.rs index 550b96e..61769c6 100644 --- a/ehttp/src/lib.rs +++ b/ehttp/src/lib.rs @@ -27,6 +27,7 @@ /// /// `Err` can happen for a number of reasons: /// * No internet connection +/// * Connection timed out /// * DNS resolution failed /// * Firewall or proxy blocked the request /// * Server is not reachable @@ -54,6 +55,7 @@ pub fn fetch(request: Request, on_done: impl 'static + Send + FnOnce(Result crate::Result { let mut req = ureq::request(&request.method, &request.url); + if let Some(timeout) = request.timeout { + req = req.timeout(timeout); + } + for (k, v) in &request.headers { req = req.set(k, v); } diff --git a/ehttp/src/types.rs b/ehttp/src/types.rs index 86b4557..9adaec2 100644 --- a/ehttp/src/types.rs +++ b/ehttp/src/types.rs @@ -1,3 +1,5 @@ +use std::time::Duration; + #[cfg(feature = "json")] use serde::Serialize; @@ -145,9 +147,14 @@ pub struct Request { /// /// Used on Web to control CORS. pub mode: Mode, + + /// Cancel the request if it doesn't complete fast enough. + pub timeout: Option, } impl Request { + pub const DEFAULT_TIMEOUT: Duration = Duration::from_secs(30); + /// Create a `GET` request with the given url. #[allow(clippy::needless_pass_by_value)] pub fn get(url: impl ToString) -> Self { @@ -157,6 +164,7 @@ impl Request { body: vec![], headers: Headers::new(&[("Accept", "*/*")]), mode: Mode::default(), + timeout: Some(Self::DEFAULT_TIMEOUT), } } @@ -169,6 +177,7 @@ impl Request { body: vec![], headers: Headers::new(&[("Accept", "*/*")]), mode: Mode::default(), + timeout: Some(Self::DEFAULT_TIMEOUT), } } @@ -184,6 +193,7 @@ impl Request { ("Content-Type", "text/plain; charset=utf-8"), ]), mode: Mode::default(), + timeout: Some(Self::DEFAULT_TIMEOUT), } } @@ -209,6 +219,7 @@ impl Request { /// .unwrap(), /// ); /// ehttp::fetch(request, |result| {}); + /// ``` #[cfg(feature = "multipart")] pub fn multipart(url: impl ToString, builder: MultipartBuilder) -> Self { let (content_type, data) = builder.finish(); @@ -218,6 +229,7 @@ impl Request { body: data, headers: Headers::new(&[("Accept", "*/*"), ("Content-Type", content_type.as_str())]), mode: Mode::default(), + timeout: Some(Self::DEFAULT_TIMEOUT), } } @@ -234,6 +246,7 @@ impl Request { body: serde_json::to_string(body)?.into_bytes(), headers: Headers::new(&[("Accept", "*/*"), ("Content-Type", "application/json")]), mode: Mode::default(), + timeout: Some(Self::DEFAULT_TIMEOUT), }) } } diff --git a/ehttp/src/web.rs b/ehttp/src/web.rs index 6057af4..8449d41 100644 --- a/ehttp/src/web.rs +++ b/ehttp/src/web.rs @@ -17,6 +17,7 @@ extern "C" { /// /// `Err` can happen for a number of reasons: /// * No internet connection +/// * Connection timed out /// * DNS resolution failed /// * Firewall or proxy blocked the request /// * Server is not reachable From 157cd2c81008c1eaf4dea01f54628b661e29f086 Mon Sep 17 00:00:00 2001 From: jprochazk Date: Thu, 4 Dec 2025 18:17:02 +0100 Subject: [PATCH 2/2] add builder --- ehttp/src/types.rs | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/ehttp/src/types.rs b/ehttp/src/types.rs index 9adaec2..b69de81 100644 --- a/ehttp/src/types.rs +++ b/ehttp/src/types.rs @@ -249,6 +249,11 @@ impl Request { timeout: Some(Self::DEFAULT_TIMEOUT), }) } + + pub fn with_timeout(mut self, timeout: Option) -> Self { + self.timeout = timeout; + self + } } /// Response from a completed HTTP request.