From 1480660277164a74f374e5e3f4239ce7f10b6ea8 Mon Sep 17 00:00:00 2001 From: Deepak Lewis <192128+tailrecur@users.noreply.github.com> Date: Thu, 11 Mar 2021 09:19:15 +0100 Subject: [PATCH] Add support to configure timeout of Expect 100 behaviour `curl 0.4.35` added the option to configure the timeout value that `curl` will wait for when using an `Expect` header before sending the request body. This commit adds the ability to configure this timeout via the `Configurable` trait within `isahc`. Fixes #303 --- Cargo.toml | 2 +- src/config/mod.rs | 35 +++++++++++++++++++++++++++++++++++ src/config/request.rs | 5 +++++ 3 files changed, 41 insertions(+), 1 deletion(-) diff --git a/Cargo.toml b/Cargo.toml index f25c6fd2..2c7828c9 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -32,7 +32,7 @@ unstable-interceptors = [] [dependencies] crossbeam-utils = "0.8" -curl = "0.4.34" +curl = "0.4.35" curl-sys = "0.4.37" futures-lite = "1.11" http = "0.2.1" diff --git a/src/config/mod.rs b/src/config/mod.rs index 3a05c55b..bd7f4d9f 100644 --- a/src/config/mod.rs +++ b/src/config/mod.rs @@ -89,6 +89,41 @@ pub trait Configurable: request::WithRequestConfig { }) } + /// Set maximum time to wait for Expect 100 request before sending body. + /// + /// `curl` has internal heuristics that trigger the use of a `Expect` + /// header for large enough request bodies where the client first sends the + /// request headers along with an `Expect: 100-continue` header. The server + /// is supposed to validate the headers and respond with a `100` response + /// status code after which `curl` will send the actual request body. + /// + /// However, if the server does not respond to the initial request + /// within `CURLOPT_EXPECT_100_TIMEOUT_MS` then `curl` will send the + /// request body anyways. + /// More info: https://curl.se/libcurl/c/CURLOPT_EXPECT_100_TIMEOUT_MS.html + /// + /// If not set, a default timeout of 1 second will be used. + /// + /// # Examples + /// + /// ```no_run + /// use std::time::Duration; + /// let response = Request::post("https://httpbin.org/post") + /// .expect_100_timeout(Duration::from_millis(0)) //Send request body immediately + /// .body(())? + /// .send()?; + /// + /// let response = Request::post("https://httpbin.org/post") + /// .expect_100_timeout(Duration::from_millis(100)) //Wait for a maximum of 100ms before sending body + /// .body(())? + /// .send()?; + /// ``` + fn expect_100_timeout(self, timeout: Duration) -> Self { + self.with_config(move |config| { + config.expect_100_timeout = Some(timeout); + }) + } + /// Configure how the use of HTTP versions should be negotiated with the /// server. /// diff --git a/src/config/request.rs b/src/config/request.rs index 4df4ba77..eb8ced08 100644 --- a/src/config/request.rs +++ b/src/config/request.rs @@ -65,6 +65,7 @@ define_request_config! { // Used by curl timeout: Option, connect_timeout: Option, + expect_100_timeout: Option, version_negotiation: Option, automatic_decompression: Option, authentication: Option, @@ -102,6 +103,10 @@ impl SetOpt for RequestConfig { easy.connect_timeout(timeout)?; } + if let Some(timeout) = self.expect_100_timeout { + easy.expect_100_timeout(timeout)?; + } + if let Some(negotiation) = self.version_negotiation.as_ref() { negotiation.set_opt(easy)?; }