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