use hyper::client::{Client, Response, RequestBuilder as NetRequestBuilder};
use hyper::header::{Headers, Header, HeaderFormat, ContentType};
use hyper::method::Method as HyperMethod;
use url::Url;
use url::form_urlencoded::Serializer as FormUrlEncoded;
use url::percent_encoding::{utf8_percent_encode, DEFAULT_ENCODE_SET};
use std::borrow::{Borrow, Cow};
use std::fmt::{self, Write};
use std::mem;
use adapter::{AbsAdapter, AdapterConsts};
use mpmc::Sender;
use net::body::{Body, EmptyFields, EagerBody, RawBody};
use net::call::Call;
use net::intercept::Interceptor;
use net::method::{Method, TakesBody};
use net::response::FromResponse;
use executor::ExecBox;
use serialize::{Serializer, Deserializer};
use ::Result;
#[derive(Debug)]
pub struct RequestHead {
url: Cow<'static, str>,
query: String,
method: HyperMethod,
headers: Headers
}
impl RequestHead {
fn new(method: HyperMethod, url: Cow<'static, str>) -> Self {
RequestHead {
url: url.into(),
query: String::new(),
method: method,
headers: Headers::new(),
}
}
pub fn header<H: Header + HeaderFormat>(&mut self, header: H) -> &mut Self {
self.headers.set(header);
self
}
pub fn headers(&mut self, headers: &Headers) -> &mut Self {
self.headers.extend(headers.iter());
self
}
pub fn append_url<A: AsRef<str>>(&mut self, append: A) -> &mut Self {
self.url.to_mut().extend(utf8_percent_encode(append.as_ref(), DEFAULT_ENCODE_SET));
self
}
pub fn prepend_url<P: AsRef<str>>(&mut self, prepend: P) -> &mut Self {
prepend_str(prepend.as_ref(), self.url.to_mut());
self
}
pub fn query<Q, P, K, V>(&mut self, query: Q) -> &mut Self
where Q: IntoIterator<Item=P>, P: Borrow<(K, V)>, K: fmt::Display, V: fmt::Display {
let mut query_out = FormUrlEncoded::new(mem::replace(&mut self.query, String::new()));
let mut kbuf = String::new();
let mut vbuf = String::new();
for pair in query {
let &(ref key, ref val) = pair.borrow();
kbuf.clear();
vbuf.clear();
write!(kbuf, "{}", key).expect("Error returned from Display::fmt()");
write!(vbuf, "{}", val).expect("Error returned from Display::fmt()");
query_out.append_pair(&kbuf, &vbuf);
}
self.query = query_out.finish();
self
}
pub fn init_request<'c>(&self, base_url: Option<&Url>, client: &'c Client) -> Result<NetRequestBuilder<'c>> {
let mut url = if let Some(base_url) = base_url {
try!(base_url.join(&self.url))
} else {
try!(Url::parse(&self.url))
};
url.set_query(Some(&self.query));
Ok(client.request(self.method.clone(), url).headers(self.headers.clone()))
}
pub fn get_url(&self) -> &str {
&self.url
}
pub fn get_query(&self) -> &str {
&self.query
}
pub fn get_method(&self) -> &HyperMethod {
&self.method
}
pub fn get_headers(&self) -> &Headers {
&self.headers
}
}
impl fmt::Display for RequestHead {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "{} {}{}", self.method, self.url, self.query)
}
}
#[derive(Debug)]
pub struct RequestBuilder<'a, A: 'a + ?Sized, M, B> {
head: RequestHead,
method: M,
body: B,
adapter: &'a A,
}
impl<'a, A: 'a + ?Sized, M> RequestBuilder<'a, A, M, EmptyFields> where M: Method {
pub fn new(adapter: &'a A, method: M, url: Cow<'static, str>) -> Self {
RequestBuilder {
adapter: adapter,
head: RequestHead::new(method.to_hyper(), url),
method: method,
body: EmptyFields,
}
}
}
impl<'a, A: 'a + ?Sized, M, B> RequestBuilder<'a, A, M, B> {
pub fn head(&self) -> &RequestHead {
&self.head
}
pub fn head_mut(&mut self) -> &mut RequestHead {
&mut self.head
}
pub fn apply<F, B_>(self, functor: F) -> Result<RequestBuilder<'a, A, M, B_>>
where F: FnOnce(Self) -> Result<RequestBuilder<'a, A, M, B_>> {
functor(self)
}
#[doc(hidden)]
pub fn swap_method<M_>(self, method: M_) -> (RequestBuilder<'a, A, M_, B>, M) {
let old_method = self.method;
(
RequestBuilder {
head: self.head,
method: method,
body: self.body,
adapter: self.adapter,
},
old_method
)
}
}
impl<'a, A: 'a + ?Sized, M, B> RequestBuilder<'a, A, M, B> where A: AbsAdapter, M: TakesBody {
pub fn body<B_>(self, body: B_) -> RequestBuilder<'a, A, M, B_> {
RequestBuilder {
adapter: self.adapter,
head: self.head,
method: self.method,
body: body,
}
}
pub fn body_eager<B_>(self, body: B_)
-> Result<RequestBuilder<'a, A, M, RawBody<<B_ as EagerBody>::Readable>>>
where B_: EagerBody {
let body = try!(body.into_readable(&self.adapter.ref_consts().serializer)).into();
Ok(self.body(body))
}
}
impl<'a, A: 'a + ?Sized, M, B> RequestBuilder<'a, A, M, B> where A: AbsAdapter {
pub fn build<T>(self) -> Request<'a, T> where B: Body, T: FromResponse {
let RequestBuilder {
adapter, head, method: _method, body
} = self;
let consts = adapter.consts();
let interceptor = adapter.interceptor();
let (mut guard, call) = super::call::oneshot(Some(head));
let exec = ExecRequest {
sender: &adapter.ref_consts().sender,
exec: Box::new(move || {
let interceptor = interceptor.as_ref().map(|i| &**i);
let res = exec_request(&consts, interceptor, guard.head_mut(), body)
.and_then(|response| T::from_response(&consts.deserializer, response));
guard.complete(res);
}),
};
Request {
exec: Some(exec),
call: call,
}
}
}
struct ExecRequest<'a> {
sender: &'a Sender,
exec: Box<ExecBox>,
}
impl<'a> ExecRequest<'a> {
fn exec(self) {
self.sender.send(self.exec);
}
fn exec_here(self) {
self.exec.exec();
}
}
#[must_use = "Request has not been sent yet"]
pub struct Request<'a, T = ()> {
exec: Option<ExecRequest<'a>>,
call: Call<T>,
}
impl<'a, T> Request<'a, T> {
pub fn immediate(res: Result<T>) -> Request<'static, T> {
Request {
exec: None,
call: super::call::immediate(res),
}
}
pub fn exec_here(self) -> Result<T> {
self.exec.map(ExecRequest::exec_here);
self.call.block()
}
pub fn is_immediate(&self) -> bool {
self.call.is_available()
}
}
impl<'a, T> Request<'a, T> where T: Send + 'static {
pub fn exec(self) -> Call<T> {
self.exec.map(ExecRequest::exec);
self.call
}
pub fn on_complete<F, R>(self, on_complete: F) -> Request<'a, R>
where F: FnOnce(T) -> R + Send + 'static, R: Send + 'static {
self.on_result(|res| res.map(on_complete))
}
pub fn on_result<F, R>(self, on_result: F) -> Request<'a, R>
where F: FnOnce(Result<T>) -> Result<R> + Send + 'static, R: Send + 'static {
let Request { exec, call } = self;
if call.is_available() {
let res = on_result(call.block());
return Request::immediate(res);
}
let ExecRequest { exec, sender } = exec.expect("`self.exec` was `None` when it shouldn't be");
let (mut guard, new_call) = super::call::oneshot(None);
let new_exec = ExecRequest {
sender: sender,
exec: Box::new(move || {
exec.exec();
guard.complete(
on_result(call.block())
);
})
};
Request {
exec: Some(new_exec),
call: new_call,
}
}
}
fn exec_request<S, D, B>(consts: &AdapterConsts<S, D>, interceptor: Option<&Interceptor>, head: &mut RequestHead, body: B) -> Result<Response>
where S: Serializer, D: Deserializer, B: Body {
if let Some(interceptor) = interceptor {
interceptor.intercept(head);
}
let mut readable = try!(body.into_readable(&consts.serializer));
if let Some(content_type) = readable.content_type {
head.header(ContentType(content_type));
}
head.init_request(consts.base_url.as_ref(), &consts.client)?
.body(&mut readable.readable).send().map_err(Into::into)
}
#[cfg(feature = "nightly")]
fn prepend_str(prepend: &str, to: &mut String) {
to.insert_str(0, prepend);
}
#[cfg(not(feature = "nightly"))]
fn prepend_str(prepend: &str, to: &mut String) {
*to = prepend.to_string() + to;
}