use std::fmt;
use serde::Serialize;
use serde_json;
use serde_urlencoded;
use super::body::{self, Body};
use super::client::{Client, Pending, pending_err};
use header::{ContentType, Headers};
use {Method, Url};
pub struct Request {
method: Method,
url: Url,
headers: Headers,
body: Option<Body>,
}
pub struct RequestBuilder {
client: Client,
request: Option<Request>,
err: Option<::Error>,
}
impl Request {
#[inline]
pub fn new(method: Method, url: Url) -> Self {
Request {
method,
url,
headers: Headers::new(),
body: None,
}
}
#[inline]
pub fn method(&self) -> &Method {
&self.method
}
#[inline]
pub fn method_mut(&mut self) -> &mut Method {
&mut self.method
}
#[inline]
pub fn url(&self) -> &Url {
&self.url
}
#[inline]
pub fn url_mut(&mut self) -> &mut Url {
&mut self.url
}
#[inline]
pub fn headers(&self) -> &Headers {
&self.headers
}
#[inline]
pub fn headers_mut(&mut self) -> &mut Headers {
&mut self.headers
}
#[inline]
pub fn body(&self) -> Option<&Body> {
self.body.as_ref()
}
#[inline]
pub fn body_mut(&mut self) -> &mut Option<Body> {
&mut self.body
}
}
impl RequestBuilder {
pub fn header<H>(&mut self, header: H) -> &mut RequestBuilder
where
H: ::header::Header,
{
if let Some(req) = request_mut(&mut self.request, &self.err) {
req.headers_mut().set(header);
}
self
}
pub fn headers(&mut self, headers: ::header::Headers) -> &mut RequestBuilder {
if let Some(req) = request_mut(&mut self.request, &self.err) {
req.headers_mut().extend(headers.iter());
}
self
}
pub fn basic_auth<U, P>(&mut self, username: U, password: Option<P>) -> &mut RequestBuilder
where
U: Into<String>,
P: Into<String>,
{
self.header(::header::Authorization(::header::Basic {
username: username.into(),
password: password.map(|p| p.into()),
}))
}
pub fn body<T: Into<Body>>(&mut self, body: T) -> &mut RequestBuilder {
if let Some(req) = request_mut(&mut self.request, &self.err) {
*req.body_mut() = Some(body.into());
}
self
}
pub fn form<T: Serialize>(&mut self, form: &T) -> &mut RequestBuilder {
if let Some(req) = request_mut(&mut self.request, &self.err) {
match serde_urlencoded::to_string(form) {
Ok(body) => {
req.headers_mut().set(ContentType::form_url_encoded());
*req.body_mut() = Some(body.into());
},
Err(err) => self.err = Some(::error::from(err)),
}
}
self
}
pub fn json<T: Serialize>(&mut self, json: &T) -> &mut RequestBuilder {
if let Some(req) = request_mut(&mut self.request, &self.err) {
match serde_json::to_vec(json) {
Ok(body) => {
req.headers_mut().set(ContentType::json());
*req.body_mut() = Some(body.into());
},
Err(err) => self.err = Some(::error::from(err)),
}
}
self
}
pub fn build(&mut self) -> ::Result<Request> {
if let Some(err) = self.err.take() {
Err(err)
} else {
Ok(self.request
.take()
.expect("RequestBuilder cannot be reused after builder a Request"))
}
}
pub fn send(&mut self) -> Pending {
match self.build() {
Ok(req) => self.client.execute(req),
Err(err) => pending_err(err),
}
}
}
fn request_mut<'a>(req: &'a mut Option<Request>, err: &Option<::Error>) -> Option<&'a mut Request> {
if err.is_some() {
None
} else {
req.as_mut()
}
}
impl fmt::Debug for Request {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
fmt_request_fields(&mut f.debug_struct("Request"), self)
.finish()
}
}
impl fmt::Debug for RequestBuilder {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
if let Some(ref req) = self.request {
fmt_request_fields(&mut f.debug_struct("RequestBuilder"), req)
.finish()
} else {
f.debug_tuple("RequestBuilder")
.field(&"Consumed")
.finish()
}
}
}
fn fmt_request_fields<'a, 'b>(f: &'a mut fmt::DebugStruct<'a, 'b>, req: &Request) -> &'a mut fmt::DebugStruct<'a, 'b> {
f.field("method", &req.method)
.field("url", &req.url)
.field("headers", &req.headers)
}
#[inline]
pub fn builder(client: Client, req: ::Result<Request>) -> RequestBuilder {
match req {
Ok(req) => RequestBuilder {
client: client,
request: Some(req),
err: None,
},
Err(err) => RequestBuilder {
client: client,
request: None,
err: Some(err)
},
}
}
#[inline]
pub fn pieces(req: Request) -> (Method, Url, Headers, Option<Body>) {
(req.method, req.url, req.headers, req.body)
}
#[cfg(test)]
mod tests {
}