Add https_only() for ClientBuilder (#1102)

Closes #980
This commit is contained in:
Martin André
2020-12-09 19:40:46 +01:00
committed by GitHub
parent 474d9eff9b
commit 541d0c2aba
4 changed files with 70 additions and 0 deletions

View File

@@ -106,6 +106,7 @@ struct Config {
cookie_store: Option<cookie::CookieStore>, cookie_store: Option<cookie::CookieStore>,
trust_dns: bool, trust_dns: bool,
error: Option<crate::Error>, error: Option<crate::Error>,
https_only: bool,
} }
impl Default for ClientBuilder { impl Default for ClientBuilder {
@@ -157,6 +158,7 @@ impl ClientBuilder {
trust_dns: cfg!(feature = "trust-dns"), trust_dns: cfg!(feature = "trust-dns"),
#[cfg(feature = "cookies")] #[cfg(feature = "cookies")]
cookie_store: None, cookie_store: None,
https_only: false,
}, },
} }
} }
@@ -349,6 +351,7 @@ impl ClientBuilder {
request_timeout: config.timeout, request_timeout: config.timeout,
proxies, proxies,
proxies_maybe_http_auth, proxies_maybe_http_auth,
https_only: config.https_only,
}), }),
}) })
} }
@@ -917,6 +920,14 @@ impl ClientBuilder {
self self
} }
} }
/// Restrict the Client to be used with HTTPS only requests.
///
/// Defaults to false.
pub fn https_only(mut self, enabled: bool) -> ClientBuilder {
self.config.https_only = enabled;
self
}
} }
type HyperClient = hyper::Client<Connector, super::body::ImplStream>; type HyperClient = hyper::Client<Connector, super::body::ImplStream>;
@@ -1040,6 +1051,11 @@ impl Client {
return Pending::new_err(error::url_bad_scheme(url)); return Pending::new_err(error::url_bad_scheme(url));
} }
// check if we're in https_only mode and check the scheme of the current URL
if self.inner.https_only && url.scheme() != "https" {
return Pending::new_err(error::url_bad_scheme(url));
}
// insert default headers in the request headers // insert default headers in the request headers
// without overwriting already appended headers. // without overwriting already appended headers.
for (key, value) in &self.inner.headers { for (key, value) in &self.inner.headers {
@@ -1238,6 +1254,7 @@ struct ClientRef {
request_timeout: Option<Duration>, request_timeout: Option<Duration>,
proxies: Arc<Vec<Proxy>>, proxies: Arc<Vec<Proxy>>,
proxies_maybe_http_auth: bool, proxies_maybe_http_auth: bool,
https_only: bool,
} }
impl ClientRef { impl ClientRef {

View File

@@ -573,6 +573,13 @@ impl ClientBuilder {
self.with_inner(|inner| inner.no_trust_dns()) self.with_inner(|inner| inner.no_trust_dns())
} }
/// Restrict the Client to be used with HTTPS only requests.
///
/// Defaults to false.
pub fn https_only(self, enabled: bool) -> ClientBuilder {
self.with_inner(|inner| inner.https_only(enabled))
}
// private // private
fn with_inner<F>(mut self, func: F) -> ClientBuilder fn with_inner<F>(mut self, func: F) -> ClientBuilder

View File

@@ -288,3 +288,25 @@ fn test_blocking_inside_a_runtime() {
let _should_panic = reqwest::blocking::get(&url); let _should_panic = reqwest::blocking::get(&url);
}); });
} }
#[cfg(feature = "default-tls")]
#[test]
fn test_allowed_methods_blocking() {
let resp = reqwest::blocking::Client::builder()
.https_only(true)
.build()
.expect("client builder")
.get("https://google.com")
.send();
assert_eq!(resp.is_err(), false);
let resp = reqwest::blocking::Client::builder()
.https_only(true)
.build()
.expect("client builder")
.get("http://google.com")
.send();
assert_eq!(resp.is_err(), true);
}

View File

@@ -199,3 +199,27 @@ fn use_preconfigured_rustls_default() {
.build() .build()
.expect("preconfigured rustls tls"); .expect("preconfigured rustls tls");
} }
#[cfg(feature = "default-tls")]
#[tokio::test]
async fn test_allowed_methods() {
let resp = reqwest::Client::builder()
.https_only(true)
.build()
.expect("client builder")
.get("https://google.com")
.send()
.await;
assert_eq!(resp.is_err(), false);
let resp = reqwest::Client::builder()
.https_only(true)
.build()
.expect("client builder")
.get("http://google.com")
.send()
.await;
assert_eq!(resp.is_err(), true);
}