diff --git a/Cargo.toml b/Cargo.toml index 8a0e715992..9130a3ec24 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -48,6 +48,7 @@ static-ssl = ["curl-sys/static-ssl"] force-system-lib-on-osx = ['curl-sys/force-system-lib-on-osx'] protocol-ftp = ["curl-sys/protocol-ftp"] zlib-ng-compat = ["curl-sys/zlib-ng-compat", "static-curl"] +upkeep_7_62_0 = ["curl-sys/upkeep_7_62_0"] [[test]] name = "atexit" diff --git a/README.md b/README.md index 252785ddfb..34bd93ee60 100644 --- a/README.md +++ b/README.md @@ -128,6 +128,7 @@ with various Cargo features: - `static-curl`: Use a bundled libcurl version and statically link to it. Disabled by default. - `static-ssl`: Use a bundled OpenSSL version and statically link to it. Only applies on platforms that use OpenSSL. Disabled by default. - `spnego`: Enable SPNEGO support. Disabled by default. +- `upkeep_7_62_0`: Enable curl_easy_upkeep() support, introduced in curl 7.62.0. Disabled by default. ## Version Support diff --git a/curl-sys/Cargo.toml b/curl-sys/Cargo.toml index 3fb97444f7..50c2bd7a8b 100644 --- a/curl-sys/Cargo.toml +++ b/curl-sys/Cargo.toml @@ -52,3 +52,4 @@ spnego = [] force-system-lib-on-osx = [] protocol-ftp = [] zlib-ng-compat = ["libz-sys/zlib-ng", "static-curl"] +upkeep_7_62_0 = [] \ No newline at end of file diff --git a/curl-sys/lib.rs b/curl-sys/lib.rs index cf039d09f4..71c09c2e4e 100644 --- a/curl-sys/lib.rs +++ b/curl-sys/lib.rs @@ -1030,6 +1030,9 @@ extern "C" { n: *mut size_t, ) -> CURLcode; + #[cfg(feature = "upkeep_7_62_0")] + pub fn curl_easy_upkeep(curl: *mut CURL) -> CURLcode; + pub fn curl_multi_init() -> *mut CURLM; pub fn curl_multi_add_handle(multi_handle: *mut CURLM, curl_handle: *mut CURL) -> CURLMcode; pub fn curl_multi_remove_handle(multi_handle: *mut CURLM, curl_handle: *mut CURL) -> CURLMcode; diff --git a/src/easy/handle.rs b/src/easy/handle.rs index b59430ebbb..b3eb64b3be 100644 --- a/src/easy/handle.rs +++ b/src/easy/handle.rs @@ -1256,6 +1256,12 @@ impl Easy { } } + /// Same as [`Easy2::upkeep`](struct.Easy2.html#method.upkeep) + #[cfg(feature = "upkeep_7_62_0")] + pub fn upkeep(&self) -> Result<(), Error> { + self.inner.upkeep() + } + /// Same as [`Easy2::unpause_read`](struct.Easy2.html#method.unpause_read) pub fn unpause_read(&self) -> Result<(), Error> { self.inner.unpause_read() @@ -1504,6 +1510,12 @@ impl<'easy, 'data> Transfer<'easy, 'data> { self.easy.do_perform() } + /// Same as `Easy::upkeep` + #[cfg(feature = "upkeep_7_62_0")] + pub fn upkeep(&self) -> Result<(), Error> { + self.easy.upkeep() + } + /// Same as `Easy::unpause_read`. pub fn unpause_read(&self) -> Result<(), Error> { self.easy.unpause_read() diff --git a/src/easy/handler.rs b/src/easy/handler.rs index afb5b86243..91181b1c8e 100644 --- a/src/easy/handler.rs +++ b/src/easy/handler.rs @@ -2737,6 +2737,21 @@ impl Easy2 { ret } + /// Some protocols have "connection upkeep" mechanisms. These mechanisms + /// usually send some traffic on existing connections in order to keep them + /// alive; this can prevent connections from being closed due to overzealous + /// firewalls, for example. + /// + /// Currently the only protocol with a connection upkeep mechanism is + /// HTTP/2: when the connection upkeep interval is exceeded and upkeep() is + /// called, an HTTP/2 PING frame is sent on the connection. + #[cfg(feature = "upkeep_7_62_0")] + pub fn upkeep(&self) -> Result<(), Error> { + let ret = unsafe { self.cvt(curl_sys::curl_easy_upkeep(self.inner.handle)) }; + panic::propagate(); + return ret; + } + /// Unpause reading on a connection. /// /// Using this function, you can explicitly unpause a connection that was diff --git a/tests/easy.rs b/tests/easy.rs index d9ab00faa3..d2d158b47f 100644 --- a/tests/easy.rs +++ b/tests/easy.rs @@ -828,3 +828,24 @@ fn check_unix_socket() { t!(h.post_fields_copy(b"data\n")); t!(h.perform()); } + +#[cfg(feature = "upkeep_7_62_0")] +#[test] +fn test_upkeep() { + let s = Server::new(); + s.receive( + "\ + GET / HTTP/1.1\r\n\ + Host: 127.0.0.1:$PORT\r\n\ + Accept: */*\r\n\ + \r\n", + ); + s.send("HTTP/1.1 200 OK\r\n\r\n"); + + let mut handle = handle(); + t!(handle.url(&s.url("/"))); + t!(handle.perform()); + + // Ensure that upkeep can be called on the handle without problem. + t!(handle.upkeep()); +}