1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185
//! Configuration for `HttpClient`s.
use std::sync::Arc;
use std::{collections::HashMap, fmt::Debug, time::Duration};
use http_client::{Config as HttpConfig, HttpClient};
use http_types::headers::{HeaderName, HeaderValues, ToHeaderValues};
use crate::http::Url;
use crate::Result;
/// Configuration for `surf::Client`s and their underlying HTTP clients.
///
/// ```
/// use std::convert::TryInto;
/// use surf::{Client, Config, Url};
///
/// # #[async_std::main]
/// # async fn main() -> surf::Result<()> {
/// let client: Client = Config::new()
/// .set_base_url(Url::parse("https://example.org")?)
/// .try_into()?;
///
/// let mut response = client.get("/").await?;
///
/// println!("{}", response.body_string().await?);
/// # Ok(())
/// # }
/// ```
#[non_exhaustive]
#[derive(Clone, Debug)]
pub struct Config {
/// The base URL for a client. All request URLs will be relative to this URL.
///
/// Note: a trailing slash is significant.
/// Without it, the last path component is considered to be a “file” name
/// to be removed to get at the “directory” that is used as the base.
pub base_url: Option<Url>,
/// Headers to be applied to every request made by this client.
pub headers: HashMap<HeaderName, HeaderValues>,
/// Underlying HTTP client config.
pub http_config: HttpConfig,
/// Optional custom http client.
pub http_client: Option<Arc<dyn HttpClient>>,
}
impl Config {
/// Construct new empty config.
pub fn new() -> Self {
Self::default()
}
}
impl Default for Config {
fn default() -> Self {
HttpConfig::default().into()
}
}
impl Config {
/// Sets the base URL for this client. All request URLs will be relative to this URL.
///
/// Note: a trailing slash is significant.
/// Without it, the last path component is considered to be a “file” name
/// to be removed to get at the “directory” that is used as the base.
///
/// ```
/// use std::convert::TryInto;
/// use surf::{Client, Config, Url};
///
/// # fn main() -> surf::Result<()> {
/// let client: Client = Config::new()
/// .set_base_url(Url::parse("https://example.org")?)
/// .try_into()?;
/// # Ok(())
/// # }
/// ```
pub fn set_base_url(mut self, base: Url) -> Self {
self.base_url = Some(base);
self
}
/// Adds a header to be added to every request by this client.
///
/// ```
/// use std::convert::TryInto;
/// use surf::{Client, Config};
/// use surf::http::auth::BasicAuth;
///
/// # fn main() -> surf::Result<()> {
/// let auth = BasicAuth::new("Username", "Password");
///
/// let client: Client = Config::new()
/// .add_header(auth.name(), auth.value())?
/// .try_into()?;
/// # Ok(())
/// # }
/// ```
pub fn add_header(
mut self,
name: impl Into<HeaderName>,
values: impl ToHeaderValues,
) -> Result<Self> {
self.headers
.insert(name.into(), values.to_header_values()?.collect());
Ok(self)
}
/// Set HTTP/1.1 `keep-alive` (connection pooling).
pub fn set_http_keep_alive(mut self, keep_alive: bool) -> Self {
self.http_config.http_keep_alive = keep_alive;
self
}
/// Set TCP `NO_DELAY`.
pub fn set_tcp_no_delay(mut self, no_delay: bool) -> Self {
self.http_config.tcp_no_delay = no_delay;
self
}
/// Set connection timeout duration.
///
/// ```
/// use std::convert::TryInto;
/// use std::time::Duration;
/// use surf::{Client, Config};
///
/// # fn main() -> surf::Result<()> {
/// let client: Client = Config::new()
/// .set_timeout(Some(Duration::from_secs(5)))
/// .try_into()?;
/// # Ok(())
/// # }
/// ```
pub fn set_timeout(mut self, timeout: Option<Duration>) -> Self {
self.http_config.timeout = timeout;
self
}
/// Set the maximum number of simultaneous connections that this client is allowed to keep open to individual hosts at one time.
pub fn set_max_connections_per_host(mut self, max_connections_per_host: usize) -> Self {
self.http_config.max_connections_per_host = max_connections_per_host;
self
}
/// Override the http client entirely.
///
/// When using this, any underlying `http_client::Config` http configuration will be ignored.
///
/// ```
/// use std::convert::TryInto;
/// use surf::{Client, Config};
///
/// # fn main() -> surf::Result<()> {
/// // Connect directly to a Tide server, e.g. for testing.
/// let server = tide::new();
///
/// let client: Client = Config::new()
/// .set_http_client(server)
/// .try_into()?;
/// # Ok(())
/// # }
/// ```
pub fn set_http_client(mut self, http_client: impl HttpClient) -> Self {
self.http_client = Some(Arc::new(http_client));
self
}
}
impl AsRef<HttpConfig> for Config {
fn as_ref(&self) -> &HttpConfig {
&self.http_config
}
}
impl From<HttpConfig> for Config {
fn from(http_config: HttpConfig) -> Self {
Self {
base_url: None,
headers: HashMap::new(),
http_config,
http_client: None,
}
}
}