Don't set User-Agent header by default (#751)
This commit is contained in:
		| @@ -1,3 +1,4 @@ | |||||||
|  | use std::convert::TryInto; | ||||||
| use std::net::IpAddr; | use std::net::IpAddr; | ||||||
| use std::sync::Arc; | use std::sync::Arc; | ||||||
| #[cfg(feature = "cookies")] | #[cfg(feature = "cookies")] | ||||||
| @@ -36,8 +37,6 @@ use crate::tls::TlsBackend; | |||||||
| use crate::{Certificate, Identity}; | use crate::{Certificate, Identity}; | ||||||
| use crate::{IntoUrl, Method, Proxy, StatusCode, Url}; | use crate::{IntoUrl, Method, Proxy, StatusCode, Url}; | ||||||
|  |  | ||||||
| static DEFAULT_USER_AGENT: &str = concat!(env!("CARGO_PKG_NAME"), "/", env!("CARGO_PKG_VERSION")); |  | ||||||
|  |  | ||||||
| /// An asynchronous `Client` to make Requests with. | /// An asynchronous `Client` to make Requests with. | ||||||
| /// | /// | ||||||
| /// The Client has various configuration values to tweak, but the defaults | /// The Client has various configuration values to tweak, but the defaults | ||||||
| @@ -85,6 +84,7 @@ struct Config { | |||||||
|     nodelay: bool, |     nodelay: bool, | ||||||
|     #[cfg(feature = "cookies")] |     #[cfg(feature = "cookies")] | ||||||
|     cookie_store: Option<cookie::CookieStore>, |     cookie_store: Option<cookie::CookieStore>, | ||||||
|  |     error: Option<crate::Error>, | ||||||
| } | } | ||||||
|  |  | ||||||
| impl Default for ClientBuilder { | impl Default for ClientBuilder { | ||||||
| @@ -99,11 +99,11 @@ impl ClientBuilder { | |||||||
|     /// This is the same as `Client::builder()`. |     /// This is the same as `Client::builder()`. | ||||||
|     pub fn new() -> ClientBuilder { |     pub fn new() -> ClientBuilder { | ||||||
|         let mut headers: HeaderMap<HeaderValue> = HeaderMap::with_capacity(2); |         let mut headers: HeaderMap<HeaderValue> = HeaderMap::with_capacity(2); | ||||||
|         headers.insert(USER_AGENT, HeaderValue::from_static(DEFAULT_USER_AGENT)); |  | ||||||
|         headers.insert(ACCEPT, HeaderValue::from_static("*/*")); |         headers.insert(ACCEPT, HeaderValue::from_static("*/*")); | ||||||
|  |  | ||||||
|         ClientBuilder { |         ClientBuilder { | ||||||
|             config: Config { |             config: Config { | ||||||
|  |                 error: None, | ||||||
|                 gzip: cfg!(feature = "gzip"), |                 gzip: cfg!(feature = "gzip"), | ||||||
|                 headers, |                 headers, | ||||||
|                 #[cfg(feature = "native-tls")] |                 #[cfg(feature = "native-tls")] | ||||||
| @@ -143,6 +143,11 @@ impl ClientBuilder { | |||||||
|     /// cannot load the system configuration. |     /// cannot load the system configuration. | ||||||
|     pub fn build(self) -> crate::Result<Client> { |     pub fn build(self) -> crate::Result<Client> { | ||||||
|         let config = self.config; |         let config = self.config; | ||||||
|  |  | ||||||
|  |         if let Some(err) = config.error { | ||||||
|  |             return Err(err); | ||||||
|  |         } | ||||||
|  |  | ||||||
|         let mut proxies = config.proxies; |         let mut proxies = config.proxies; | ||||||
|         if config.auto_sys_proxy { |         if config.auto_sys_proxy { | ||||||
|             proxies.push(Proxy::system()); |             proxies.push(Proxy::system()); | ||||||
| @@ -151,8 +156,8 @@ impl ClientBuilder { | |||||||
|  |  | ||||||
|         let mut connector = { |         let mut connector = { | ||||||
|             #[cfg(feature = "__tls")] |             #[cfg(feature = "__tls")] | ||||||
|             fn user_agent(headers: &HeaderMap) -> HeaderValue { |             fn user_agent(headers: &HeaderMap) -> Option<HeaderValue> { | ||||||
|                 headers[USER_AGENT].clone() |                 headers.get(USER_AGENT).cloned() | ||||||
|             } |             } | ||||||
|  |  | ||||||
|             #[cfg(feature = "__tls")] |             #[cfg(feature = "__tls")] | ||||||
| @@ -270,6 +275,42 @@ impl ClientBuilder { | |||||||
|  |  | ||||||
|     // Higher-level options |     // Higher-level options | ||||||
|  |  | ||||||
|  |  | ||||||
|  |     /// Sets the `User-Agent` header to be used by this client. | ||||||
|  |     /// | ||||||
|  |     /// # Example | ||||||
|  |     /// | ||||||
|  |     /// ```rust | ||||||
|  |     /// # async fn doc() -> Result<(), reqwest::Error> { | ||||||
|  |     /// // Name your user agent after your app? | ||||||
|  |     /// static APP_USER_AGENT: &str = concat!( | ||||||
|  |     ///     env!("CARGO_PKG_NAME"), | ||||||
|  |     ///     "/", | ||||||
|  |     ///     env!("CARGO_PKG_VERSION"), | ||||||
|  |     /// ); | ||||||
|  |     /// | ||||||
|  |     /// let client = reqwest::Client::builder() | ||||||
|  |     ///     .user_agent(APP_USER_AGENT) | ||||||
|  |     ///     .build()?; | ||||||
|  |     /// let res = client.get("https://www.rust-lang.org").send().await?; | ||||||
|  |     /// # Ok(()) | ||||||
|  |     /// # } | ||||||
|  |     /// ``` | ||||||
|  |     pub fn user_agent<V>(mut self, value: V) -> ClientBuilder | ||||||
|  |     where | ||||||
|  |         V: TryInto<HeaderValue>, | ||||||
|  |         V::Error: Into<http::Error>, | ||||||
|  |     { | ||||||
|  |         match value.try_into() { | ||||||
|  |             Ok(value) => { | ||||||
|  |                 self.config.headers.insert(USER_AGENT, value); | ||||||
|  |             } | ||||||
|  |             Err(e) => { | ||||||
|  |                 self.config.error = Some(crate::error::builder(e.into())); | ||||||
|  |             } | ||||||
|  |         }; | ||||||
|  |         self | ||||||
|  |     } | ||||||
|     /// Sets the default headers for every request. |     /// Sets the default headers for every request. | ||||||
|     /// |     /// | ||||||
|     /// # Example |     /// # Example | ||||||
|   | |||||||
| @@ -1,3 +1,4 @@ | |||||||
|  | use std::convert::TryInto; | ||||||
| use std::fmt; | use std::fmt; | ||||||
| use std::future::Future; | use std::future::Future; | ||||||
| use std::net::IpAddr; | use std::net::IpAddr; | ||||||
| @@ -5,6 +6,7 @@ use std::sync::Arc; | |||||||
| use std::thread; | use std::thread; | ||||||
| use std::time::Duration; | use std::time::Duration; | ||||||
|  |  | ||||||
|  | use http::header::HeaderValue; | ||||||
| use log::{error, trace}; | use log::{error, trace}; | ||||||
| use tokio::sync::{mpsc, oneshot}; | use tokio::sync::{mpsc, oneshot}; | ||||||
|  |  | ||||||
| @@ -85,6 +87,35 @@ impl ClientBuilder { | |||||||
|  |  | ||||||
|     // Higher-level options |     // Higher-level options | ||||||
|  |  | ||||||
|  |  | ||||||
|  |     /// Sets the `User-Agent` header to be used by this client. | ||||||
|  |     /// | ||||||
|  |     /// # Example | ||||||
|  |     /// | ||||||
|  |     /// ```rust | ||||||
|  |     /// # fn doc() -> Result<(), reqwest::Error> { | ||||||
|  |     /// // Name your user agent after your app? | ||||||
|  |     /// static APP_USER_AGENT: &str = concat!( | ||||||
|  |     ///     env!("CARGO_PKG_NAME"), | ||||||
|  |     ///     "/", | ||||||
|  |     ///     env!("CARGO_PKG_VERSION"), | ||||||
|  |     /// ); | ||||||
|  |     /// | ||||||
|  |     /// let client = reqwest::blocking::Client::builder() | ||||||
|  |     ///     .user_agent(APP_USER_AGENT) | ||||||
|  |     ///     .build()?; | ||||||
|  |     /// let res = client.get("https://www.rust-lang.org").send()?; | ||||||
|  |     /// # Ok(()) | ||||||
|  |     /// # } | ||||||
|  |     /// ``` | ||||||
|  |     pub fn user_agent<V>(self, value: V) -> ClientBuilder | ||||||
|  |     where | ||||||
|  |         V: TryInto<HeaderValue>, | ||||||
|  |         V::Error: Into<http::Error>, | ||||||
|  |     { | ||||||
|  |         self.with_inner(move |inner| inner.user_agent(value)) | ||||||
|  |     } | ||||||
|  |  | ||||||
|     /// Sets the default headers for every request. |     /// Sets the default headers for every request. | ||||||
|     /// |     /// | ||||||
|     /// # Example |     /// # Example | ||||||
|   | |||||||
| @@ -41,7 +41,7 @@ pub(crate) struct Connector { | |||||||
|     #[cfg(feature = "__tls")] |     #[cfg(feature = "__tls")] | ||||||
|     nodelay: bool, |     nodelay: bool, | ||||||
|     #[cfg(feature = "__tls")] |     #[cfg(feature = "__tls")] | ||||||
|     user_agent: HeaderValue, |     user_agent: Option<HeaderValue>, | ||||||
| } | } | ||||||
|  |  | ||||||
| #[derive(Clone)] | #[derive(Clone)] | ||||||
| @@ -82,7 +82,7 @@ impl Connector { | |||||||
|     pub(crate) fn new_default_tls<T>( |     pub(crate) fn new_default_tls<T>( | ||||||
|         tls: TlsConnectorBuilder, |         tls: TlsConnectorBuilder, | ||||||
|         proxies: Arc<Vec<Proxy>>, |         proxies: Arc<Vec<Proxy>>, | ||||||
|         user_agent: HeaderValue, |         user_agent: Option<HeaderValue>, | ||||||
|         local_addr: T, |         local_addr: T, | ||||||
|         nodelay: bool, |         nodelay: bool, | ||||||
|     ) -> crate::Result<Connector> |     ) -> crate::Result<Connector> | ||||||
| @@ -108,7 +108,7 @@ impl Connector { | |||||||
|     pub(crate) fn new_rustls_tls<T>( |     pub(crate) fn new_rustls_tls<T>( | ||||||
|         tls: rustls::ClientConfig, |         tls: rustls::ClientConfig, | ||||||
|         proxies: Arc<Vec<Proxy>>, |         proxies: Arc<Vec<Proxy>>, | ||||||
|         user_agent: HeaderValue, |         user_agent: Option<HeaderValue>, | ||||||
|         local_addr: T, |         local_addr: T, | ||||||
|         nodelay: bool, |         nodelay: bool, | ||||||
|     ) -> crate::Result<Connector> |     ) -> crate::Result<Connector> | ||||||
| @@ -515,7 +515,7 @@ async fn tunnel<T>( | |||||||
|     mut conn: T, |     mut conn: T, | ||||||
|     host: String, |     host: String, | ||||||
|     port: u16, |     port: u16, | ||||||
|     user_agent: HeaderValue, |     user_agent: Option<HeaderValue>, | ||||||
|     auth: Option<HeaderValue>, |     auth: Option<HeaderValue>, | ||||||
| ) -> Result<T, io::Error> | ) -> Result<T, io::Error> | ||||||
| where | where | ||||||
| @@ -534,9 +534,11 @@ where | |||||||
|  |  | ||||||
|  |  | ||||||
|     // user-agent |     // user-agent | ||||||
|  |     if let Some(user_agent) = user_agent { | ||||||
|         buf.extend_from_slice(b"User-Agent: "); |         buf.extend_from_slice(b"User-Agent: "); | ||||||
|         buf.extend_from_slice(user_agent.as_bytes()); |         buf.extend_from_slice(user_agent.as_bytes()); | ||||||
|         buf.extend_from_slice(b"\r\n"); |         buf.extend_from_slice(b"\r\n"); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |  | ||||||
|     // proxy-authorization |     // proxy-authorization | ||||||
| @@ -888,8 +890,8 @@ mod tests { | |||||||
|         }}; |         }}; | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     fn ua() -> http::header::HeaderValue { |     fn ua() -> Option<http::header::HeaderValue> { | ||||||
|         http::header::HeaderValue::from_static(TUNNEL_UA) |         Some(http::header::HeaderValue::from_static(TUNNEL_UA)) | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     #[test] |     #[test] | ||||||
|   | |||||||
| @@ -11,7 +11,7 @@ async fn auto_headers() { | |||||||
|             assert_eq!(req.method(), "GET"); |             assert_eq!(req.method(), "GET"); | ||||||
|  |  | ||||||
|             assert_eq!(req.headers()["accept"], "*/*"); |             assert_eq!(req.headers()["accept"], "*/*"); | ||||||
|             assert_eq!(req.headers()["user-agent"], DEFAULT_USER_AGENT); |             assert_eq!(req.headers().get("user-agent"), None); | ||||||
|             if cfg!(feature = "gzip") { |             if cfg!(feature = "gzip") { | ||||||
|                 assert_eq!(req.headers()["accept-encoding"], "gzip"); |                 assert_eq!(req.headers()["accept-encoding"], "gzip"); | ||||||
|             } |             } | ||||||
| @@ -28,6 +28,28 @@ async fn auto_headers() { | |||||||
|     assert_eq!(res.remote_addr(), Some(server.addr())); |     assert_eq!(res.remote_addr(), Some(server.addr())); | ||||||
| } | } | ||||||
|  |  | ||||||
|  | #[tokio::test] | ||||||
|  | async fn user_agent() { | ||||||
|  |     let server = server::http(move |req| { | ||||||
|  |         async move { | ||||||
|  |             assert_eq!(req.headers()["user-agent"], "reqwest-test-agent"); | ||||||
|  |             http::Response::default() | ||||||
|  |         } | ||||||
|  |     }); | ||||||
|  |  | ||||||
|  |     let url = format!("http://{}/ua", server.addr()); | ||||||
|  |     let res = reqwest::Client::builder() | ||||||
|  |         .user_agent("reqwest-test-agent") | ||||||
|  |         .build() | ||||||
|  |         .expect("client builder") | ||||||
|  |         .get(&url) | ||||||
|  |         .send() | ||||||
|  |         .await | ||||||
|  |         .expect("request"); | ||||||
|  |  | ||||||
|  |     assert_eq!(res.status(), reqwest::StatusCode::OK); | ||||||
|  | } | ||||||
|  |  | ||||||
| #[tokio::test] | #[tokio::test] | ||||||
| async fn response_text() { | async fn response_text() { | ||||||
|     let _ = env_logger::try_init(); |     let _ = env_logger::try_init(); | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user