Turn Option<AgentState> into AgentState (#149)
`Some(AgentState)` seem to be assumed pretty much everywhere. I could not find any test or piece of code hinting at how `None` should be interpreted, or even see how a state of `None` could even be constructed. Co-authored-by: Ulrik <ulrikm@spotify.com>
This commit is contained in:
27
src/agent.rs
27
src/agent.rs
@@ -40,13 +40,13 @@ pub struct Agent {
|
||||
/// Copied into each request of this agent.
|
||||
pub(crate) headers: Vec<Header>,
|
||||
/// Reused agent state for repeated requests from this agent.
|
||||
pub(crate) state: Arc<Mutex<Option<AgentState>>>,
|
||||
pub(crate) state: Arc<Mutex<AgentState>>,
|
||||
}
|
||||
|
||||
/// Container of the state
|
||||
///
|
||||
/// *Internal API*.
|
||||
#[derive(Debug)]
|
||||
#[derive(Debug, Default)]
|
||||
pub(crate) struct AgentState {
|
||||
/// Reused connections between requests.
|
||||
pub(crate) pool: ConnectionPool,
|
||||
@@ -89,7 +89,7 @@ impl Agent {
|
||||
pub fn build(&self) -> Self {
|
||||
Agent {
|
||||
headers: self.headers.clone(),
|
||||
state: Arc::new(Mutex::new(Some(AgentState::new()))),
|
||||
state: Arc::new(Mutex::new(AgentState::new())),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -175,11 +175,9 @@ impl Agent {
|
||||
/// agent.set_max_pool_connections(200);
|
||||
/// ```
|
||||
pub fn set_max_pool_connections(&self, max_connections: usize) {
|
||||
let mut optional_state = self.state.lock().unwrap();
|
||||
if let Some(state) = optional_state.as_mut() {
|
||||
let mut state = self.state.lock().unwrap();
|
||||
state.pool.set_max_idle_connections(max_connections);
|
||||
}
|
||||
}
|
||||
|
||||
/// Sets the maximum number of connections per host to keep in the
|
||||
/// connection pool. By default, this is set to 1. Setting this to zero
|
||||
@@ -190,13 +188,11 @@ impl Agent {
|
||||
/// agent.set_max_pool_connections_per_host(10);
|
||||
/// ```
|
||||
pub fn set_max_pool_connections_per_host(&self, max_connections: usize) {
|
||||
let mut optional_state = self.state.lock().unwrap();
|
||||
if let Some(state) = optional_state.as_mut() {
|
||||
let mut state = self.state.lock().unwrap();
|
||||
state
|
||||
.pool
|
||||
.set_max_idle_connections_per_host(max_connections);
|
||||
}
|
||||
}
|
||||
|
||||
/// Gets a cookie in this agent by name. Cookies are available
|
||||
/// either by setting it in the agent, or by making requests
|
||||
@@ -212,10 +208,7 @@ impl Agent {
|
||||
#[cfg(feature = "cookie")]
|
||||
pub fn cookie(&self, name: &str) -> Option<Cookie<'static>> {
|
||||
let state = self.state.lock().unwrap();
|
||||
state
|
||||
.as_ref()
|
||||
.and_then(|state| state.jar.get(name))
|
||||
.cloned()
|
||||
state.jar.get(name).cloned()
|
||||
}
|
||||
|
||||
/// Set a cookie in this agent.
|
||||
@@ -229,13 +222,8 @@ impl Agent {
|
||||
#[cfg(feature = "cookie")]
|
||||
pub fn set_cookie(&self, cookie: Cookie<'static>) {
|
||||
let mut state = self.state.lock().unwrap();
|
||||
match state.as_mut() {
|
||||
None => (),
|
||||
Some(state) => {
|
||||
state.jar.add_original(cookie);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Make a GET request from this agent.
|
||||
pub fn get(&self, path: &str) -> Request {
|
||||
@@ -321,8 +309,7 @@ mod tests {
|
||||
reader.read_to_end(&mut buf).unwrap();
|
||||
|
||||
fn poolsize(agent: &Agent) -> usize {
|
||||
let mut lock = agent.state.lock().unwrap();
|
||||
let state = lock.as_mut().unwrap();
|
||||
let mut state = agent.state.lock().unwrap();
|
||||
state.pool().len()
|
||||
}
|
||||
assert_eq!(poolsize(&agent), 1);
|
||||
|
||||
@@ -381,15 +381,13 @@ impl<R: Read + Sized + Into<Stream>> PoolReturnRead<R> {
|
||||
let state = &mut unit.agent.lock().unwrap();
|
||||
// bring back stream here to either go into pool or dealloc
|
||||
let stream = reader.into();
|
||||
if let Some(agent) = state.as_mut() {
|
||||
if !stream.is_poolable() {
|
||||
// just let it deallocate
|
||||
return;
|
||||
}
|
||||
// insert back into pool
|
||||
let key = PoolKey::new(&unit.url, &unit.proxy);
|
||||
agent.pool().add(key, stream);
|
||||
}
|
||||
state.pool().add(key, stream);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -29,7 +29,7 @@ use super::SerdeValue;
|
||||
/// ```
|
||||
#[derive(Clone, Default)]
|
||||
pub struct Request {
|
||||
pub(crate) agent: Arc<Mutex<Option<AgentState>>>,
|
||||
pub(crate) agent: Arc<Mutex<AgentState>>,
|
||||
|
||||
// via agent
|
||||
pub(crate) method: String,
|
||||
|
||||
@@ -78,8 +78,7 @@ fn connection_reuse() {
|
||||
resp.into_string().unwrap();
|
||||
|
||||
{
|
||||
let mut guard_state = agent.state.lock().unwrap();
|
||||
let mut state = guard_state.take().unwrap();
|
||||
let mut state = agent.state.lock().unwrap();
|
||||
assert!(state.pool().len() > 0);
|
||||
}
|
||||
|
||||
|
||||
20
src/unit.rs
20
src/unit.rs
@@ -27,9 +27,8 @@ use crate::pool::DEFAULT_HOST;
|
||||
/// It's a "unit of work". Maybe a bad name for it?
|
||||
///
|
||||
/// *Internal API*
|
||||
#[derive(Debug)]
|
||||
pub(crate) struct Unit {
|
||||
pub agent: Arc<Mutex<Option<AgentState>>>,
|
||||
pub agent: Arc<Mutex<AgentState>>,
|
||||
pub url: Url,
|
||||
pub is_chunked: bool,
|
||||
pub query_string: String,
|
||||
@@ -239,19 +238,16 @@ pub(crate) fn connect(
|
||||
}
|
||||
|
||||
#[cfg(feature = "cookie")]
|
||||
fn extract_cookies(state: &std::sync::Mutex<Option<AgentState>>, url: &Url) -> Option<Header> {
|
||||
fn extract_cookies(state: &std::sync::Mutex<AgentState>, url: &Url) -> Option<Header> {
|
||||
let state = state.lock().unwrap();
|
||||
let is_secure = url.scheme().eq_ignore_ascii_case("https");
|
||||
let hostname = url.host_str().unwrap_or(DEFAULT_HOST).to_string();
|
||||
|
||||
state
|
||||
.as_ref()
|
||||
.map(|state| &state.jar)
|
||||
.and_then(|jar| match_cookies(jar, &hostname, url.path(), is_secure))
|
||||
match_cookies(&state.jar, &hostname, url.path(), is_secure)
|
||||
}
|
||||
|
||||
#[cfg(not(feature = "cookie"))]
|
||||
fn extract_cookies(_state: &std::sync::Mutex<Option<AgentState>>, _url: &Url) -> Option<Header> {
|
||||
fn extract_cookies(_state: &std::sync::Mutex<AgentState>, _url: &Url) -> Option<Header> {
|
||||
None
|
||||
}
|
||||
|
||||
@@ -309,18 +305,16 @@ fn connect_socket(unit: &Unit, use_pooled: bool) -> Result<(Stream, bool), Error
|
||||
};
|
||||
if use_pooled {
|
||||
let state = &mut unit.agent.lock().unwrap();
|
||||
if let Some(agent) = state.as_mut() {
|
||||
// The connection may have been closed by the server
|
||||
// due to idle timeout while it was sitting in the pool.
|
||||
// Loop until we find one that is still good or run out of connections.
|
||||
while let Some(stream) = agent.pool.try_get_connection(&unit.url, &unit.proxy) {
|
||||
while let Some(stream) = state.pool.try_get_connection(&unit.url, &unit.proxy) {
|
||||
let server_closed = stream.server_closed()?;
|
||||
if !server_closed {
|
||||
return Ok((stream, true));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
let stream = match unit.url.scheme() {
|
||||
"http" => stream::connect_http(&unit),
|
||||
"https" => stream::connect_https(&unit),
|
||||
@@ -406,7 +400,6 @@ fn save_cookies(unit: &Unit, resp: &Response) {
|
||||
|
||||
// only lock if we know there is something to process
|
||||
let state = &mut unit.agent.lock().unwrap();
|
||||
if let Some(add_jar) = state.as_mut().map(|state| &mut state.jar) {
|
||||
for raw_cookie in cookies.iter() {
|
||||
let to_parse = if raw_cookie.to_lowercase().contains("domain=") {
|
||||
(*raw_cookie).to_string()
|
||||
@@ -418,8 +411,7 @@ fn save_cookies(unit: &Unit, resp: &Response) {
|
||||
Err(_) => (), // ignore unparseable cookies
|
||||
Ok(cookie) => {
|
||||
let cookie = cookie.into_owned();
|
||||
add_jar.add(cookie)
|
||||
}
|
||||
state.jar.add(cookie)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user