move all configuration from Client to ClientBuilder
This commit is contained in:
134
src/client.rs
134
src/client.rs
@@ -1,6 +1,5 @@
|
|||||||
use std::fmt;
|
use std::fmt;
|
||||||
use std::sync::{Arc, Mutex, RwLock};
|
use std::sync::Arc;
|
||||||
use std::sync::atomic::{AtomicBool, Ordering};
|
|
||||||
use std::time::Duration;
|
use std::time::Duration;
|
||||||
|
|
||||||
use hyper::client::IntoUrl;
|
use hyper::client::IntoUrl;
|
||||||
@@ -114,7 +113,11 @@ pub struct ClientBuilder {
|
|||||||
}
|
}
|
||||||
|
|
||||||
struct Config {
|
struct Config {
|
||||||
|
gzip: bool,
|
||||||
hostname_verification: bool,
|
hostname_verification: bool,
|
||||||
|
redirect_policy: RedirectPolicy,
|
||||||
|
referer: bool,
|
||||||
|
timeout: Option<Duration>,
|
||||||
tls: native_tls::TlsConnectorBuilder,
|
tls: native_tls::TlsConnectorBuilder,
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -127,7 +130,11 @@ impl ClientBuilder {
|
|||||||
);
|
);
|
||||||
Ok(ClientBuilder {
|
Ok(ClientBuilder {
|
||||||
config: Some(Config {
|
config: Some(Config {
|
||||||
|
gzip: true,
|
||||||
hostname_verification: true,
|
hostname_verification: true,
|
||||||
|
redirect_policy: RedirectPolicy::default(),
|
||||||
|
referer: true,
|
||||||
|
timeout: None,
|
||||||
tls: tls_connector_builder,
|
tls: tls_connector_builder,
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
@@ -161,13 +168,15 @@ impl ClientBuilder {
|
|||||||
);
|
);
|
||||||
|
|
||||||
hyper_client.set_redirect_policy(::hyper::client::RedirectPolicy::FollowNone);
|
hyper_client.set_redirect_policy(::hyper::client::RedirectPolicy::FollowNone);
|
||||||
|
hyper_client.set_read_timeout(config.timeout);
|
||||||
|
hyper_client.set_write_timeout(config.timeout);
|
||||||
|
|
||||||
Ok(Client {
|
Ok(Client {
|
||||||
inner: Arc::new(ClientRef {
|
inner: Arc::new(ClientRef {
|
||||||
hyper: RwLock::new(hyper_client),
|
gzip: config.gzip,
|
||||||
redirect_policy: Mutex::new(RedirectPolicy::default()),
|
hyper: hyper_client,
|
||||||
auto_referer: AtomicBool::new(true),
|
redirect_policy: config.redirect_policy,
|
||||||
auto_ungzip: AtomicBool::new(true),
|
referer: config.referer,
|
||||||
}),
|
}),
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
@@ -194,13 +203,51 @@ impl ClientBuilder {
|
|||||||
/// hostname verification is not used, any valid certificate for any
|
/// hostname verification is not used, any valid certificate for any
|
||||||
/// site will be trusted for use from any other. This introduces a
|
/// site will be trusted for use from any other. This introduces a
|
||||||
/// significant vulnerability to man-in-the-middle attacks.
|
/// significant vulnerability to man-in-the-middle attacks.
|
||||||
pub fn danger_disable_hostname_verification(&mut self) {
|
#[inline]
|
||||||
|
pub fn danger_disable_hostname_verification(&mut self) -> &mut ClientBuilder {
|
||||||
self.config_mut().hostname_verification = false;
|
self.config_mut().hostname_verification = false;
|
||||||
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Enable hostname verification.
|
/// Enable hostname verification.
|
||||||
pub fn enable_hostname_verification(&mut self) {
|
#[inline]
|
||||||
|
pub fn enable_hostname_verification(&mut self) -> &mut ClientBuilder {
|
||||||
self.config_mut().hostname_verification = true;
|
self.config_mut().hostname_verification = true;
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Enable auto gzip decompression by checking the ContentEncoding response header.
|
||||||
|
///
|
||||||
|
/// Default is enabled.
|
||||||
|
#[inline]
|
||||||
|
pub fn gzip(&mut self, enable: bool) -> &mut ClientBuilder {
|
||||||
|
self.config_mut().gzip = enable;
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Set a `RedirectPolicy` for this client.
|
||||||
|
///
|
||||||
|
/// Default will follow redirects up to a maximum of 10.
|
||||||
|
#[inline]
|
||||||
|
pub fn redirect(&mut self, policy: RedirectPolicy) -> &mut ClientBuilder {
|
||||||
|
self.config_mut().redirect_policy = policy;
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Enable or disable automatic setting of the `Referer` header.
|
||||||
|
///
|
||||||
|
/// Default is `true`.
|
||||||
|
#[inline]
|
||||||
|
pub fn referer(&mut self, enable: bool) -> &mut ClientBuilder {
|
||||||
|
self.config_mut().referer = enable;
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Set a timeout for both the read and write operations of a client.
|
||||||
|
#[inline]
|
||||||
|
pub fn timeout(&mut self, timeout: Duration) -> &mut ClientBuilder {
|
||||||
|
self.config_mut().timeout = Some(timeout);
|
||||||
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
// private
|
// private
|
||||||
@@ -219,36 +266,15 @@ impl ClientBuilder {
|
|||||||
|
|
||||||
impl Client {
|
impl Client {
|
||||||
/// Constructs a new `Client`.
|
/// Constructs a new `Client`.
|
||||||
|
#[inline]
|
||||||
pub fn new() -> ::Result<Client> {
|
pub fn new() -> ::Result<Client> {
|
||||||
try_!(ClientBuilder::new()).build()
|
ClientBuilder::new()?.build()
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Enable auto gzip decompression by checking the ContentEncoding response header.
|
/// Creates a `ClientBuilder` to configure a `Client`.
|
||||||
///
|
#[inline]
|
||||||
/// Default is enabled.
|
pub fn builder() -> ::Result<ClientBuilder> {
|
||||||
pub fn gzip(&mut self, enable: bool) {
|
ClientBuilder::new()
|
||||||
self.inner.auto_ungzip.store(enable, Ordering::Relaxed);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Set a `RedirectPolicy` for this client.
|
|
||||||
///
|
|
||||||
/// Default will follow redirects up to a maximum of 10.
|
|
||||||
pub fn redirect(&mut self, policy: RedirectPolicy) {
|
|
||||||
*self.inner.redirect_policy.lock().unwrap() = policy;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Enable or disable automatic setting of the `Referer` header.
|
|
||||||
///
|
|
||||||
/// Default is `true`.
|
|
||||||
pub fn referer(&mut self, enable: bool) {
|
|
||||||
self.inner.auto_referer.store(enable, Ordering::Relaxed);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Set a timeout for both the read and write operations of a client.
|
|
||||||
pub fn timeout(&mut self, timeout: Duration) {
|
|
||||||
let mut client = self.inner.hyper.write().unwrap();
|
|
||||||
client.set_read_timeout(Some(timeout));
|
|
||||||
client.set_write_timeout(Some(timeout));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Convenience method to make a `GET` request to a URL.
|
/// Convenience method to make a `GET` request to a URL.
|
||||||
@@ -288,7 +314,7 @@ impl Client {
|
|||||||
pub fn request<U: IntoUrl>(&self, method: Method, url: U) -> RequestBuilder {
|
pub fn request<U: IntoUrl>(&self, method: Method, url: U) -> RequestBuilder {
|
||||||
let url = url.into_url();
|
let url = url.into_url();
|
||||||
RequestBuilder {
|
RequestBuilder {
|
||||||
client: self.inner.clone(),
|
client: self.clone(),
|
||||||
method: method,
|
method: method,
|
||||||
url: url,
|
url: url,
|
||||||
_version: HttpVersion::Http11,
|
_version: HttpVersion::Http11,
|
||||||
@@ -313,18 +339,18 @@ impl Client {
|
|||||||
impl fmt::Debug for Client {
|
impl fmt::Debug for Client {
|
||||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||||
f.debug_struct("Client")
|
f.debug_struct("Client")
|
||||||
|
.field("gzip", &self.inner.gzip)
|
||||||
.field("redirect_policy", &self.inner.redirect_policy)
|
.field("redirect_policy", &self.inner.redirect_policy)
|
||||||
.field("referer", &self.inner.auto_referer)
|
.field("referer", &self.inner.referer)
|
||||||
.field("auto_ungzip", &self.inner.auto_ungzip)
|
|
||||||
.finish()
|
.finish()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
struct ClientRef {
|
struct ClientRef {
|
||||||
hyper: RwLock<::hyper::Client>,
|
gzip: bool,
|
||||||
redirect_policy: Mutex<RedirectPolicy>,
|
hyper: ::hyper::Client,
|
||||||
auto_referer: AtomicBool,
|
redirect_policy: RedirectPolicy,
|
||||||
auto_ungzip: AtomicBool,
|
referer: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ClientRef {
|
impl ClientRef {
|
||||||
@@ -337,7 +363,7 @@ impl ClientRef {
|
|||||||
if !headers.has::<Accept>() {
|
if !headers.has::<Accept>() {
|
||||||
headers.set(Accept::star());
|
headers.set(Accept::star());
|
||||||
}
|
}
|
||||||
if self.auto_ungzip.load(Ordering::Relaxed) &&
|
if self.gzip &&
|
||||||
!headers.has::<AcceptEncoding>() &&
|
!headers.has::<AcceptEncoding>() &&
|
||||||
!headers.has::<Range>() {
|
!headers.has::<Range>() {
|
||||||
headers.set(AcceptEncoding(vec![qitem(Encoding::Gzip)]));
|
headers.set(AcceptEncoding(vec![qitem(Encoding::Gzip)]));
|
||||||
@@ -351,8 +377,7 @@ impl ClientRef {
|
|||||||
loop {
|
loop {
|
||||||
let res = {
|
let res = {
|
||||||
info!("Request: {:?} {}", method, url);
|
info!("Request: {:?} {}", method, url);
|
||||||
let c = self.hyper.read().unwrap();
|
let mut req = self.hyper.request(method.clone(), url.clone())
|
||||||
let mut req = c.request(method.clone(), url.clone())
|
|
||||||
.headers(headers.clone());
|
.headers(headers.clone());
|
||||||
|
|
||||||
if let Some(ref mut b) = body {
|
if let Some(ref mut b) = body {
|
||||||
@@ -393,25 +418,25 @@ impl ClientRef {
|
|||||||
if let Some(loc) = loc {
|
if let Some(loc) = loc {
|
||||||
loc
|
loc
|
||||||
} else {
|
} else {
|
||||||
return Ok(::response::new(res, self.auto_ungzip.load(Ordering::Relaxed)));
|
return Ok(::response::new(res, self.gzip));
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
url = match loc {
|
url = match loc {
|
||||||
Ok(loc) => {
|
Ok(loc) => {
|
||||||
if self.auto_referer.load(Ordering::Relaxed) {
|
if self.referer {
|
||||||
if let Some(referer) = make_referer(&loc, &url) {
|
if let Some(referer) = make_referer(&loc, &url) {
|
||||||
headers.set(referer);
|
headers.set(referer);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
urls.push(url);
|
urls.push(url);
|
||||||
let action = check_redirect(&self.redirect_policy.lock().unwrap(), &loc, &urls);
|
let action = check_redirect(&self.redirect_policy, &loc, &urls);
|
||||||
|
|
||||||
match action {
|
match action {
|
||||||
redirect::Action::Follow => loc,
|
redirect::Action::Follow => loc,
|
||||||
redirect::Action::Stop => {
|
redirect::Action::Stop => {
|
||||||
debug!("redirect_policy disallowed redirection to '{}'", loc);
|
debug!("redirect_policy disallowed redirection to '{}'", loc);
|
||||||
return Ok(::response::new(res, self.auto_ungzip.load(Ordering::Relaxed)));
|
return Ok(::response::new(res, self.gzip));
|
||||||
},
|
},
|
||||||
redirect::Action::LoopDetected => {
|
redirect::Action::LoopDetected => {
|
||||||
return Err(::error::loop_detected(res.url.clone()));
|
return Err(::error::loop_detected(res.url.clone()));
|
||||||
@@ -424,14 +449,14 @@ impl ClientRef {
|
|||||||
Err(e) => {
|
Err(e) => {
|
||||||
debug!("Location header had invalid URI: {:?}", e);
|
debug!("Location header had invalid URI: {:?}", e);
|
||||||
|
|
||||||
return Ok(::response::new(res, self.auto_ungzip.load(Ordering::Relaxed)))
|
return Ok(::response::new(res, self.gzip));
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
remove_sensitive_headers(&mut headers, &url, &urls);
|
remove_sensitive_headers(&mut headers, &url, &urls);
|
||||||
debug!("redirecting to {:?} '{}'", method, url);
|
debug!("redirecting to {:?} '{}'", method, url);
|
||||||
} else {
|
} else {
|
||||||
return Ok(::response::new(res, self.auto_ungzip.load(Ordering::Relaxed)))
|
return Ok(::response::new(res, self.gzip));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -439,7 +464,6 @@ impl ClientRef {
|
|||||||
|
|
||||||
/// A request which can be executed with `Client::execute()`.
|
/// A request which can be executed with `Client::execute()`.
|
||||||
pub struct Request {
|
pub struct Request {
|
||||||
_version: HttpVersion,
|
|
||||||
method: Method,
|
method: Method,
|
||||||
url: Url,
|
url: Url,
|
||||||
headers: Headers,
|
headers: Headers,
|
||||||
@@ -451,7 +475,6 @@ impl Request {
|
|||||||
#[inline]
|
#[inline]
|
||||||
pub fn new(method: Method, url: Url) -> Self {
|
pub fn new(method: Method, url: Url) -> Self {
|
||||||
Request {
|
Request {
|
||||||
_version: HttpVersion::Http11,
|
|
||||||
method,
|
method,
|
||||||
url,
|
url,
|
||||||
headers: Headers::new(),
|
headers: Headers::new(),
|
||||||
@@ -510,7 +533,7 @@ impl Request {
|
|||||||
|
|
||||||
/// A builder to construct the properties of a `Request`.
|
/// A builder to construct the properties of a `Request`.
|
||||||
pub struct RequestBuilder {
|
pub struct RequestBuilder {
|
||||||
client: Arc<ClientRef>,
|
client: Client,
|
||||||
|
|
||||||
method: Method,
|
method: Method,
|
||||||
url: Result<Url, ::UrlError>,
|
url: Result<Url, ::UrlError>,
|
||||||
@@ -638,7 +661,6 @@ impl RequestBuilder {
|
|||||||
None => None,
|
None => None,
|
||||||
};
|
};
|
||||||
let req = Request {
|
let req = Request {
|
||||||
_version: self._version,
|
|
||||||
method: self.method,
|
method: self.method,
|
||||||
url: url,
|
url: url,
|
||||||
headers: self.headers,
|
headers: self.headers,
|
||||||
@@ -651,7 +673,7 @@ impl RequestBuilder {
|
|||||||
pub fn send(self) -> ::Result<Response> {
|
pub fn send(self) -> ::Result<Response> {
|
||||||
let client = self.client.clone();
|
let client = self.client.clone();
|
||||||
let request = self.build()?;
|
let request = self.build()?;
|
||||||
client.execute_request(request)
|
client.execute(request)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -62,8 +62,7 @@ impl RedirectPolicy {
|
|||||||
/// # use reqwest::{Error, RedirectPolicy};
|
/// # use reqwest::{Error, RedirectPolicy};
|
||||||
/// #
|
/// #
|
||||||
/// # fn run() -> Result<(), Error> {
|
/// # fn run() -> Result<(), Error> {
|
||||||
/// let mut client = reqwest::Client::new()?;
|
/// let custom = RedirectPolicy::custom(|attempt| {
|
||||||
/// client.redirect(RedirectPolicy::custom(|attempt| {
|
|
||||||
/// if attempt.previous().len() > 5 {
|
/// if attempt.previous().len() > 5 {
|
||||||
/// attempt.too_many_redirects()
|
/// attempt.too_many_redirects()
|
||||||
/// } else if attempt.url().host_str() == Some("example.domain") {
|
/// } else if attempt.url().host_str() == Some("example.domain") {
|
||||||
@@ -72,7 +71,10 @@ impl RedirectPolicy {
|
|||||||
/// } else {
|
/// } else {
|
||||||
/// attempt.follow()
|
/// attempt.follow()
|
||||||
/// }
|
/// }
|
||||||
/// }));
|
/// });
|
||||||
|
/// let client = reqwest::Client::builder()?
|
||||||
|
/// .redirect(custom)
|
||||||
|
/// .build()?;
|
||||||
/// # Ok(())
|
/// # Ok(())
|
||||||
/// # }
|
/// # }
|
||||||
/// ```
|
/// ```
|
||||||
|
|||||||
@@ -225,9 +225,11 @@ fn test_redirect_removes_sensitive_headers() {
|
|||||||
", end_server.addr())
|
", end_server.addr())
|
||||||
};
|
};
|
||||||
|
|
||||||
let mut client = reqwest::Client::new().unwrap();
|
reqwest::Client::builder()
|
||||||
client.referer(false);
|
.unwrap()
|
||||||
client
|
.referer(false)
|
||||||
|
.build()
|
||||||
|
.unwrap()
|
||||||
.get(&format!("http://{}/sensitive", mid_server.addr()))
|
.get(&format!("http://{}/sensitive", mid_server.addr()))
|
||||||
.header(reqwest::header::Cookie(vec![String::from("foo=bar")]))
|
.header(reqwest::header::Cookie(vec![String::from("foo=bar")]))
|
||||||
.send()
|
.send()
|
||||||
@@ -277,11 +279,17 @@ fn test_redirect_policy_can_stop_redirects_without_an_error() {
|
|||||||
\r\n\
|
\r\n\
|
||||||
"
|
"
|
||||||
};
|
};
|
||||||
let mut client = reqwest::Client::new().unwrap();
|
|
||||||
client.redirect(reqwest::RedirectPolicy::none());
|
|
||||||
|
|
||||||
let url = format!("http://{}/no-redirect", server.addr());
|
let url = format!("http://{}/no-redirect", server.addr());
|
||||||
let res = client.get(&url).send().unwrap();
|
|
||||||
|
let res = reqwest::Client::builder()
|
||||||
|
.unwrap()
|
||||||
|
.redirect(reqwest::RedirectPolicy::none())
|
||||||
|
.build()
|
||||||
|
.unwrap()
|
||||||
|
.get(&url)
|
||||||
|
.send()
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
assert_eq!(res.url().as_str(), url);
|
assert_eq!(res.url().as_str(), url);
|
||||||
assert_eq!(res.status(), &reqwest::StatusCode::Found);
|
assert_eq!(res.status(), &reqwest::StatusCode::Found);
|
||||||
@@ -324,9 +332,10 @@ fn test_referer_is_not_set_if_disabled() {
|
|||||||
\r\n\
|
\r\n\
|
||||||
"
|
"
|
||||||
};
|
};
|
||||||
let mut client = reqwest::Client::new().unwrap();
|
reqwest::Client::builder().unwrap()
|
||||||
client.referer(false);
|
.referer(false)
|
||||||
client
|
.build().unwrap()
|
||||||
|
//client
|
||||||
.get(&format!("http://{}/no-refer", server.addr()))
|
.get(&format!("http://{}/no-refer", server.addr()))
|
||||||
.send()
|
.send()
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
|||||||
Reference in New Issue
Block a user