Don't set User-Agent header by default (#751)

This commit is contained in:
Sean McArthur
2019-12-23 12:48:11 -08:00
committed by GitHub
parent 47734f55f4
commit 09e7fe62e3
4 changed files with 111 additions and 15 deletions

View File

@@ -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

View File

@@ -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

View File

@@ -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
buf.extend_from_slice(b"User-Agent: "); if let Some(user_agent) = user_agent {
buf.extend_from_slice(user_agent.as_bytes()); buf.extend_from_slice(b"User-Agent: ");
buf.extend_from_slice(b"\r\n"); buf.extend_from_slice(user_agent.as_bytes());
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]

View File

@@ -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();