Skip to content

Commit 43ac315

Browse files
committed
Add ability to set the request timeout for the HTTP client
1 parent ae18c75 commit 43ac315

8 files changed

Lines changed: 88 additions & 6 deletions

File tree

Cargo.toml

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
[package]
22
name = "thirtyfour"
3-
version = "0.22.0"
3+
version = "0.21.0"
44
authors = ["Steve Pryde <steve@stevepryde.com>"]
55
edition = "2018"
66
license = "MIT OR Apache-2.0"
@@ -20,7 +20,7 @@ categories = ["api-bindings", "development-tools::testing", "web-programming::ht
2020
[features]
2121
default = ["tokio-runtime", "reqwest-default-tls"]
2222
tokio-runtime = ["tokio", "reqwest"]
23-
async-std-runtime = ["async-std", "surf"]
23+
async-std-runtime = ["async-std", "surf", "isahc", "http-client"]
2424

2525
reqwest-default-tls = ["reqwest/default-tls"]
2626
reqwest-native-tls = ["reqwest/native-tls"]
@@ -32,7 +32,9 @@ async-trait = "0.1"
3232
futures = "0.3"
3333
tokio = { version = "0.2", features = ["fs", "macros", "rt-threaded", "io-util"], optional = true }
3434
reqwest = { version = "0.10", features = ["json"], optional = true }
35-
async-std = { version = "1.6", features = ["attributes"], optional = true }
35+
http-client = { version = "6.2", optional = true }
36+
isahc = { version = "0.9", optional = true }
37+
async-std = { version = "1.8", features = ["attributes"], optional = true }
3638
surf = { version = "2.0.0-alpha.5", features = ["curl-client"], optional = true }
3739
serde_json = { version = "1.0", features = ["preserve_order"] }
3840
serde = { version = "1.0", features = ["derive"] }

src/http/connection_async.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ use async_trait::async_trait;
44

55
use crate::error::WebDriverResult;
66
use crate::RequestData;
7+
use std::time::Duration;
78

89
/// Trait for executing HTTP requests to selenium/webdriver.
910
/// As long as you have some struct that implements WebDriverHttpClientAsync
@@ -19,5 +20,7 @@ pub trait WebDriverHttpClientAsync: Debug + Send + Sync {
1920
where
2021
Self: Sized;
2122

23+
fn set_request_timeout(&mut self, timeout: Duration);
24+
2225
async fn execute(&self, request_data: RequestData) -> WebDriverResult<serde_json::Value>;
2326
}

src/http/nulldriver_async.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,8 @@ impl WebDriverHttpClientAsync for NullDriverAsync {
1919
})
2020
}
2121

22+
fn set_request_timeout(&mut self, timeout: Duration) {}
23+
2224
async fn execute(&self, _request_data: RequestData) -> WebDriverResult<serde_json::Value> {
2325
Ok(serde_json::Value::Null)
2426
}

src/http/reqwest_async.rs

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,12 +8,14 @@ use crate::{
88
error::{WebDriverError, WebDriverResult},
99
RequestData, RequestMethod,
1010
};
11+
use std::time::Duration;
1112

1213
/// Asynchronous http to the remote WebDriver server.
1314
#[derive(Debug)]
1415
pub struct ReqwestDriverAsync {
1516
url: String,
1617
client: reqwest::Client,
18+
timeout: Duration,
1719
}
1820

1921
#[async_trait]
@@ -23,9 +25,14 @@ impl WebDriverHttpClientAsync for ReqwestDriverAsync {
2325
Ok(ReqwestDriverAsync {
2426
url: remote_server_addr.trim_end_matches('/').to_owned(),
2527
client: reqwest::Client::builder().default_headers(headers).build()?,
28+
timeout: Duration::from_secs(120),
2629
})
2730
}
2831

32+
fn set_request_timeout(&mut self, timeout: Duration) {
33+
self.timeout = timeout;
34+
}
35+
2936
/// Execute the specified command and return the data as serde_json::Value.
3037
async fn execute(&self, request_data: RequestData) -> WebDriverResult<serde_json::Value> {
3138
let url = self.url.clone() + &request_data.url;
@@ -34,6 +41,8 @@ impl WebDriverHttpClientAsync for ReqwestDriverAsync {
3441
RequestMethod::Post => self.client.post(&url),
3542
RequestMethod::Delete => self.client.delete(&url),
3643
};
44+
request = request.timeout(self.timeout);
45+
3746
if let Some(x) = request_data.body {
3847
request = request.json(&x);
3948
}

src/http/surf_async.rs

Lines changed: 18 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,23 +7,39 @@ use crate::{
77
error::{WebDriverError, WebDriverResult},
88
RequestData, RequestMethod,
99
};
10+
use isahc::prelude::Configurable;
11+
use std::time::Duration;
12+
use surf::Client;
1013

1114
/// Asynchronous http to the remote WebDriver server.
1215
#[derive(Debug)]
1316
pub struct SurfDriverAsync {
1417
url: String,
15-
client: surf::Client,
18+
client: Client,
19+
}
20+
21+
fn setup_client(timeout: Duration) -> Client {
22+
let backing_client =
23+
isahc::HttpClient::builder().timeout(timeout).build().expect("Error creating HTTP client");
24+
let http_client = http_client::isahc::IsahcClient::from_client(backing_client);
25+
Client::with_http_client(http_client)
1626
}
1727

1828
#[async_trait]
1929
impl WebDriverHttpClientAsync for SurfDriverAsync {
2030
fn create(remote_server_addr: &str) -> WebDriverResult<Self> {
2131
Ok(SurfDriverAsync {
2232
url: remote_server_addr.trim_end_matches('/').to_owned(),
23-
client: surf::Client::new(),
33+
client: setup_client(Duration::from_secs(120)),
2434
})
2535
}
2636

37+
fn set_request_timeout(&mut self, timeout: Duration) {
38+
// Currently it looks like the only way to increase the timeout is by recreating the client.
39+
// https://github.com/http-rs/surf/issues/267
40+
self.client = setup_client(timeout);
41+
}
42+
2743
/// Execute the specified command and return the data as serde_json::Value.
2844
async fn execute(&self, request_data: RequestData) -> WebDriverResult<serde_json::Value> {
2945
let url = self.url.clone() + &request_data.url;

src/session.rs

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,10 +9,12 @@ use futures::channel::mpsc::{unbounded, UnboundedReceiver, UnboundedSender};
99
use futures::channel::oneshot;
1010
use futures::SinkExt;
1111
use futures::StreamExt;
12+
use std::time::Duration;
1213

1314
#[derive(Debug)]
1415
pub enum SessionMessage {
1516
Request(RequestData, oneshot::Sender<WebDriverResult<serde_json::Value>>),
17+
SetRequestTimeout(Duration),
1618
}
1719

1820
pub fn spawn_session_task(
@@ -35,7 +37,7 @@ pub fn spawn_session_task(
3537

3638
async fn session_runner(
3739
mut rx: UnboundedReceiver<SessionMessage>,
38-
conn: Box<dyn WebDriverHttpClientAsync>,
40+
mut conn: Box<dyn WebDriverHttpClientAsync>,
3941
) {
4042
// This will return None when the sender hangs up.
4143
while let Some(msg) = rx.next().await {
@@ -44,6 +46,9 @@ async fn session_runner(
4446
let ret = conn.execute(data).await;
4547
tx.send(ret).expect("Failed to send response");
4648
}
49+
SessionMessage::SetRequestTimeout(timeout) => {
50+
conn.set_request_timeout(timeout);
51+
}
4752
}
4853
}
4954
}
@@ -96,6 +101,13 @@ impl WebDriverSession {
96101
)),
97102
}
98103
}
104+
105+
pub async fn set_request_timeout(&mut self, timeout: Duration) -> WebDriverResult<()> {
106+
self.tx.clone().send(SessionMessage::SetRequestTimeout(timeout)).await.map_err(|e| {
107+
WebDriverError::UnknownResponse(format!("Failed to send request to server: {}", e))
108+
})?;
109+
Ok(())
110+
}
99111
}
100112

101113
#[async_trait]

src/webdriver.rs

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ use crate::{
1919
DesiredCapabilities, SessionId,
2020
};
2121
use futures::executor::block_on;
22+
use std::time::Duration;
2223

2324
#[cfg(not(any(feature = "tokio-runtime", feature = "async-std-runtime")))]
2425
/// The WebDriver struct represents a browser session.
@@ -141,6 +142,27 @@ where
141142
pub fn config_mut(&mut self) -> &mut WebDriverConfig {
142143
self.session.config_mut()
143144
}
145+
146+
/// Set the request timeout for the HTTP client.
147+
///
148+
/// # Example
149+
/// ```rust
150+
/// # use thirtyfour::prelude::*;
151+
/// # use std::time::Duration;
152+
/// # use thirtyfour::support::block_on;
153+
/// #
154+
/// # fn main() -> WebDriverResult<()> {
155+
/// # block_on(async {
156+
/// let caps = DesiredCapabilities::chrome();
157+
/// let mut driver = WebDriver::new("http://localhost:4444/wd/hub", &caps).await?;
158+
/// driver.set_request_timeout(Duration::from_secs(180)).await?;
159+
/// # Ok(())
160+
/// # })
161+
/// # }
162+
/// ```
163+
pub async fn set_request_timeout(&mut self, timeout: Duration) -> WebDriverResult<()> {
164+
self.session.set_request_timeout(timeout).await
165+
}
144166
}
145167

146168
#[async_trait]

src/webdrivercommands.rs

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -774,6 +774,10 @@ pub trait WebDriverCommands {
774774

775775
/// Set all timeouts for the current session.
776776
///
777+
/// NOTE: If you set timeouts to values greater than 120 seconds,
778+
/// remember to also increase the request timeout.
779+
/// See `WebDriver::set_request_timeout()` for more details.
780+
///
777781
/// # Example:
778782
/// ```rust
779783
/// # use thirtyfour::prelude::*;
@@ -807,6 +811,10 @@ pub trait WebDriverCommands {
807811
/// find it more reliable to set the implicit wait time to 0 (no wait)
808812
/// and implement your own polling loop outside of `thirtyfour`.
809813
///
814+
/// NOTE: If you set timeouts to values greater than 120 seconds,
815+
/// remember to also increase the request timeout.
816+
/// See `WebDriver::set_request_timeout()` for more details.
817+
///
810818
/// # Example:
811819
/// ```rust
812820
/// # use thirtyfour::prelude::*;
@@ -836,6 +844,10 @@ pub trait WebDriverCommands {
836844
///
837845
/// By default this is set to 60 seconds.
838846
///
847+
/// NOTE: If you set timeouts to values greater than 120 seconds,
848+
/// remember to also increase the request timeout.
849+
/// See `WebDriver::set_request_timeout()` for more details.
850+
///
839851
/// # Example:
840852
/// ```rust
841853
/// # use thirtyfour::prelude::*;
@@ -865,6 +877,10 @@ pub trait WebDriverCommands {
865877
///
866878
/// By default this is set to 60 seconds.
867879
///
880+
/// NOTE: If you set timeouts to values greater than 120 seconds,
881+
/// remember to also increase the request timeout.
882+
/// See `WebDriver::set_request_timeout()` for more details.
883+
///
868884
/// # Example:
869885
/// ```rust
870886
/// # use thirtyfour::prelude::*;

0 commit comments

Comments
 (0)