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::sync::{Arc, Mutex, RwLock}; | ||||
| use std::sync::atomic::{AtomicBool, Ordering}; | ||||
| use std::sync::Arc; | ||||
| use std::time::Duration; | ||||
|  | ||||
| use hyper::client::IntoUrl; | ||||
| @@ -114,7 +113,11 @@ pub struct ClientBuilder { | ||||
| } | ||||
|  | ||||
| struct Config { | ||||
|     gzip: bool, | ||||
|     hostname_verification: bool, | ||||
|     redirect_policy: RedirectPolicy, | ||||
|     referer: bool, | ||||
|     timeout: Option<Duration>, | ||||
|     tls: native_tls::TlsConnectorBuilder, | ||||
| } | ||||
|  | ||||
| @@ -127,7 +130,11 @@ impl ClientBuilder { | ||||
|         ); | ||||
|         Ok(ClientBuilder { | ||||
|             config: Some(Config { | ||||
|                 gzip: true, | ||||
|                 hostname_verification: true, | ||||
|                 redirect_policy: RedirectPolicy::default(), | ||||
|                 referer: true, | ||||
|                 timeout: None, | ||||
|                 tls: tls_connector_builder, | ||||
|             }) | ||||
|         }) | ||||
| @@ -161,13 +168,15 @@ impl ClientBuilder { | ||||
|         ); | ||||
|  | ||||
|         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 { | ||||
|             inner: Arc::new(ClientRef { | ||||
|                 hyper: RwLock::new(hyper_client), | ||||
|                 redirect_policy: Mutex::new(RedirectPolicy::default()), | ||||
|                 auto_referer: AtomicBool::new(true), | ||||
|                 auto_ungzip: AtomicBool::new(true), | ||||
|                 gzip: config.gzip, | ||||
|                 hyper: hyper_client, | ||||
|                 redirect_policy: config.redirect_policy, | ||||
|                 referer: config.referer, | ||||
|             }), | ||||
|         }) | ||||
|     } | ||||
| @@ -194,13 +203,51 @@ impl ClientBuilder { | ||||
|     /// hostname verification is not used, any valid certificate for any | ||||
|     /// site will be trusted for use from any other. This introduces a | ||||
|     /// 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 | ||||
|     } | ||||
|  | ||||
|     /// 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 | ||||
|     } | ||||
|  | ||||
|     /// 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 | ||||
| @@ -219,36 +266,15 @@ impl ClientBuilder { | ||||
|  | ||||
| impl Client { | ||||
|     /// Constructs a new `Client`. | ||||
|     #[inline] | ||||
|     pub fn new() -> ::Result<Client> { | ||||
|         try_!(ClientBuilder::new()).build() | ||||
|         ClientBuilder::new()?.build() | ||||
|     } | ||||
|  | ||||
|     /// Enable auto gzip decompression by checking the ContentEncoding response header. | ||||
|     /// | ||||
|     /// Default is enabled. | ||||
|     pub fn gzip(&mut self, enable: bool) { | ||||
|         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)); | ||||
|     /// Creates a `ClientBuilder` to configure a `Client`. | ||||
|     #[inline] | ||||
|     pub fn builder() -> ::Result<ClientBuilder> { | ||||
|         ClientBuilder::new() | ||||
|     } | ||||
|  | ||||
|     /// 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 { | ||||
|         let url = url.into_url(); | ||||
|         RequestBuilder { | ||||
|             client: self.inner.clone(), | ||||
|             client: self.clone(), | ||||
|             method: method, | ||||
|             url: url, | ||||
|             _version: HttpVersion::Http11, | ||||
| @@ -313,18 +339,18 @@ impl Client { | ||||
| impl fmt::Debug for Client { | ||||
|     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { | ||||
|         f.debug_struct("Client") | ||||
|             .field("gzip", &self.inner.gzip) | ||||
|             .field("redirect_policy", &self.inner.redirect_policy) | ||||
|             .field("referer", &self.inner.auto_referer) | ||||
|             .field("auto_ungzip", &self.inner.auto_ungzip) | ||||
|             .field("referer", &self.inner.referer) | ||||
|             .finish() | ||||
|     } | ||||
| } | ||||
|  | ||||
| struct ClientRef { | ||||
|     hyper: RwLock<::hyper::Client>, | ||||
|     redirect_policy: Mutex<RedirectPolicy>, | ||||
|     auto_referer: AtomicBool, | ||||
|     auto_ungzip: AtomicBool, | ||||
|     gzip: bool, | ||||
|     hyper: ::hyper::Client, | ||||
|     redirect_policy: RedirectPolicy, | ||||
|     referer: bool, | ||||
| } | ||||
|  | ||||
| impl ClientRef { | ||||
| @@ -337,7 +363,7 @@ impl ClientRef { | ||||
|         if !headers.has::<Accept>() { | ||||
|             headers.set(Accept::star()); | ||||
|         } | ||||
|         if self.auto_ungzip.load(Ordering::Relaxed) && | ||||
|         if self.gzip && | ||||
|             !headers.has::<AcceptEncoding>() && | ||||
|             !headers.has::<Range>() { | ||||
|             headers.set(AcceptEncoding(vec![qitem(Encoding::Gzip)])); | ||||
| @@ -351,8 +377,7 @@ impl ClientRef { | ||||
|         loop { | ||||
|             let res = { | ||||
|                 info!("Request: {:?} {}", method, url); | ||||
|                 let c = self.hyper.read().unwrap(); | ||||
|                 let mut req = c.request(method.clone(), url.clone()) | ||||
|                 let mut req = self.hyper.request(method.clone(), url.clone()) | ||||
|                     .headers(headers.clone()); | ||||
|  | ||||
|                 if let Some(ref mut b) = body { | ||||
| @@ -393,25 +418,25 @@ impl ClientRef { | ||||
|                     if let Some(loc) = loc { | ||||
|                         loc | ||||
|                     } else { | ||||
|                         return Ok(::response::new(res, self.auto_ungzip.load(Ordering::Relaxed))); | ||||
|                         return Ok(::response::new(res, self.gzip)); | ||||
|                     } | ||||
|                 }; | ||||
|  | ||||
|                 url = match loc { | ||||
|                     Ok(loc) => { | ||||
|                         if self.auto_referer.load(Ordering::Relaxed) { | ||||
|                         if self.referer { | ||||
|                             if let Some(referer) = make_referer(&loc, &url) { | ||||
|                                 headers.set(referer); | ||||
|                             } | ||||
|                         } | ||||
|                         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 { | ||||
|                             redirect::Action::Follow => loc, | ||||
|                             redirect::Action::Stop => { | ||||
|                                 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 => { | ||||
|                                 return Err(::error::loop_detected(res.url.clone())); | ||||
| @@ -424,14 +449,14 @@ impl ClientRef { | ||||
|                     Err(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); | ||||
|                 debug!("redirecting to {:?} '{}'", method, url); | ||||
|             } 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()`. | ||||
| pub struct Request { | ||||
|     _version: HttpVersion, | ||||
|     method: Method, | ||||
|     url: Url, | ||||
|     headers: Headers, | ||||
| @@ -451,7 +475,6 @@ impl Request { | ||||
|     #[inline] | ||||
|     pub fn new(method: Method, url: Url) -> Self { | ||||
|         Request { | ||||
|             _version: HttpVersion::Http11, | ||||
|             method, | ||||
|             url, | ||||
|             headers: Headers::new(), | ||||
| @@ -510,7 +533,7 @@ impl Request { | ||||
|  | ||||
| /// A builder to construct the properties of a `Request`. | ||||
| pub struct RequestBuilder { | ||||
|     client: Arc<ClientRef>, | ||||
|     client: Client, | ||||
|  | ||||
|     method: Method, | ||||
|     url: Result<Url, ::UrlError>, | ||||
| @@ -638,7 +661,6 @@ impl RequestBuilder { | ||||
|             None => None, | ||||
|         }; | ||||
|         let req = Request { | ||||
|             _version: self._version, | ||||
|             method: self.method, | ||||
|             url: url, | ||||
|             headers: self.headers, | ||||
| @@ -651,7 +673,7 @@ impl RequestBuilder { | ||||
|     pub fn send(self) -> ::Result<Response> { | ||||
|         let client = self.client.clone(); | ||||
|         let request = self.build()?; | ||||
|         client.execute_request(request) | ||||
|         client.execute(request) | ||||
|     } | ||||
| } | ||||
|  | ||||
|   | ||||
| @@ -62,8 +62,7 @@ impl RedirectPolicy { | ||||
|     /// # use reqwest::{Error, RedirectPolicy}; | ||||
|     /// # | ||||
|     /// # fn run() -> Result<(), Error> { | ||||
|     /// let mut client = reqwest::Client::new()?; | ||||
|     /// client.redirect(RedirectPolicy::custom(|attempt| { | ||||
|     /// let custom = RedirectPolicy::custom(|attempt| { | ||||
|     ///     if attempt.previous().len() > 5 { | ||||
|     ///         attempt.too_many_redirects() | ||||
|     ///     } else if attempt.url().host_str() == Some("example.domain") { | ||||
| @@ -72,7 +71,10 @@ impl RedirectPolicy { | ||||
|     ///     } else { | ||||
|     ///         attempt.follow() | ||||
|     ///     } | ||||
|     /// })); | ||||
|     /// }); | ||||
|     /// let client = reqwest::Client::builder()? | ||||
|     ///     .redirect(custom) | ||||
|     ///     .build()?; | ||||
|     /// # Ok(()) | ||||
|     /// # } | ||||
|     /// ``` | ||||
|   | ||||
| @@ -225,9 +225,11 @@ fn test_redirect_removes_sensitive_headers() { | ||||
|             ", end_server.addr()) | ||||
|     }; | ||||
|  | ||||
|     let mut client = reqwest::Client::new().unwrap(); | ||||
|     client.referer(false); | ||||
|     client | ||||
|     reqwest::Client::builder() | ||||
|         .unwrap() | ||||
|         .referer(false) | ||||
|         .build() | ||||
|         .unwrap() | ||||
|         .get(&format!("http://{}/sensitive", mid_server.addr())) | ||||
|         .header(reqwest::header::Cookie(vec![String::from("foo=bar")])) | ||||
|         .send() | ||||
| @@ -277,11 +279,17 @@ fn test_redirect_policy_can_stop_redirects_without_an_error() { | ||||
|             \r\n\ | ||||
|             " | ||||
|     }; | ||||
|     let mut client = reqwest::Client::new().unwrap(); | ||||
|     client.redirect(reqwest::RedirectPolicy::none()); | ||||
|  | ||||
|     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.status(), &reqwest::StatusCode::Found); | ||||
| @@ -324,9 +332,10 @@ fn test_referer_is_not_set_if_disabled() { | ||||
|             \r\n\ | ||||
|             " | ||||
|     }; | ||||
|     let mut client = reqwest::Client::new().unwrap(); | ||||
|     client.referer(false); | ||||
|     client | ||||
|     reqwest::Client::builder().unwrap() | ||||
|         .referer(false) | ||||
|         .build().unwrap() | ||||
|         //client | ||||
|         .get(&format!("http://{}/no-refer", server.addr())) | ||||
|         .send() | ||||
|         .unwrap(); | ||||
|   | ||||
		Reference in New Issue
	
	Block a user