Repository: seanmonstar/reqwest (language: rust)

Issue:
[Question] How to tell if timeout is caused by Connect?
Is it possible to tell a TimedOut err is caused by connect? 
The reason is, if it is caused by connect timeout, then I can retry the request.

hyper's error has two methods for this, is_connect and is_timeout. Seems I have to downcast the boxed err to hyper err and call those two methods?


Discussion / hints:
Yes, you could check the `source()`. We could also add a `is_connect` method to `reqwest::Error`. Would you want to try adding that?

Fix patch:
diff --git a/src/error.rs b/src/error.rs
index b8e84b521..cb05eb774 100644
--- a/src/error.rs
+++ b/src/error.rs
@@ -102,6 +102,24 @@ impl Error {
         }
     }
 
+    #[cfg(not(target_arch = "wasm32"))]
+    /// Returns true if the error is related to connect
+    pub fn is_connect(&self) -> bool {
+        let mut source = self.source();
+
+        while let Some(err) = source {
+            if let Some(hyper_err) = err.downcast_ref::<hyper::Error>() {
+                if hyper_err.is_connect() {
+                    return true;
+                }
+            }
+
+            source = err.source();
+        }
+
+        false
+    }
+
     /// Returns true if the error is related to the request or response body
     pub fn is_body(&self) -> bool {
         match self.inner.kind {


Test patch:
diff --git a/tests/timeouts.rs b/tests/timeouts.rs
index 4a8880e9f..8c3a269bb 100644
--- a/tests/timeouts.rs
+++ b/tests/timeouts.rs
@@ -54,10 +54,37 @@ async fn request_timeout() {
 
     let err = res.unwrap_err();
 
-    assert!(err.is_timeout());
+    if cfg!(not(target_arch = "wasm32")) {
+        assert!(err.is_timeout() && !err.is_connect());
+    } else {
+        assert!(err.is_timeout());
+    }
     assert_eq!(err.url().map(|u| u.as_str()), Some(url.as_str()));
 }
 
+#[cfg(not(target_arch = "wasm32"))]
+#[tokio::test]
+async fn connect_timeout() {
+    let _ = env_logger::try_init();
+
+    let client = reqwest::Client::builder()
+        .connect_timeout(Duration::from_millis(100))
+        .build()
+        .unwrap();
+
+    let url = format!("http://10.255.255.1:81/slow");
+
+    let res = client
+        .get(&url)
+        .timeout(Duration::from_millis(1000))
+        .send()
+        .await;
+
+    let err = res.unwrap_err();
+
+    assert!(err.is_connect() && err.is_timeout());
+}
+
 #[tokio::test]
 async fn response_timeout() {
     let _ = env_logger::try_init();