use cookie::{Cookie, CookieJar};
use error::Error;
use pool::ConnectionPool;
use response::{self, Response};
use std::sync::Mutex;
use header::{add_header, get_all_headers, get_header, has_header, Header};
include!("request.rs");
include!("unit.rs");
#[derive(Debug, Default, Clone)]
pub struct Agent {
headers: Vec<Header>,
state: Arc<Mutex<Option<AgentState>>>,
}
#[derive(Debug)]
pub struct AgentState {
pool: ConnectionPool,
jar: CookieJar,
}
impl AgentState {
fn new() -> Self {
AgentState {
pool: ConnectionPool::new(),
jar: CookieJar::new(),
}
}
pub fn pool(&mut self) -> &mut ConnectionPool {
&mut self.pool
}
}
impl Agent {
pub fn new() -> Agent {
Default::default()
}
pub fn build(&self) -> Self {
Agent {
headers: self.headers.clone(),
state: Arc::new(Mutex::new(Some(AgentState::new()))),
}
}
pub fn set(&mut self, header: &str, value: &str) -> &mut Agent
{
add_header(
&mut self.headers,
Header::new(header, value),
);
self
}
pub fn auth(&mut self, user: &str, pass: &str) -> &mut Agent
{
let pass = basic_auth(user, pass);
self.auth_kind("Basic", &pass)
}
pub fn auth_kind(&mut self, kind: &str, pass: &str) -> &mut Agent
{
let value = format!("{} {}", kind, pass);
self.set("Authorization", &value);
self
}
pub fn request(&self, method: &str, path: &str) -> Request
{
Request::new(&self, method.into(), path.into())
}
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))
.map(|c| c.clone())
}
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);
}
}
}
pub fn get(&self, path: &str) -> Request
{
self.request("GET", path)
}
pub fn head(&self, path: &str) -> Request
{
self.request("HEAD", path)
}
pub fn post(&self, path: &str) -> Request
{
self.request("POST", path)
}
pub fn put(&self, path: &str) -> Request
{
self.request("PUT", path)
}
pub fn delete(&self, path: &str) -> Request
{
self.request("DELETE", path)
}
pub fn trace(&self, path: &str) -> Request
{
self.request("TRACE", path)
}
pub fn options(&self, path: &str) -> Request
{
self.request("OPTIONS", path)
}
pub fn connect(&self, path: &str) -> Request
{
self.request("CONNECT", path)
}
pub fn patch(&self, path: &str) -> Request
{
self.request("PATCH", path)
}
#[cfg(test)]
pub fn state(&self) -> &Arc<Mutex<Option<AgentState>>> {
&self.state
}
}
fn basic_auth(user: &str, pass: &str) -> String {
let safe = match user.find(":") {
Some(idx) => &user[..idx],
None => user,
};
::base64::encode(&format!("{}:{}", safe, pass))
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn agent_implements_send() {
let mut agent = Agent::new();
::std::thread::spawn(move || {
agent.set("Foo", "Bar");
});
}
#[test]
fn request_implements_send() {
let agent = Agent::new();
let mut request = Request::new(&agent, "GET".to_string(), "/foo".to_string());
::std::thread::spawn(move || {
request.set("Foo", "Bar");
});
}
}