simplist 0.0.5

plain and simple http, for when you just want to make a darn request! supports tokio-based async, traditional sync and async-await models.
Documentation
use std;

use futures::Future;
use futures::Stream;
use hina;
use hyper::Error as HyperError;
use hyper::Headers;
use hyper::Response;
use hyper::StatusCode;
use hyper::header::ContentLength;

use simplist::HttpError;



/// a http response, whose body can be read asynchronously.
///
/// there are two primary methods to retrieve the body for a response:
///
///   - [`fn read_as_bytes(...)`](struct.HttpResponse.html#method.read_as_bytes): returns a future that will resolve to
///     a [`Vec<u8>`](https://doc.rust-lang.org/std/vec/struct.Vec.html) that contains the response body.
///   - [`fn read_as_string(...)`](struct.HttpResponse.html#method.read_as_string): returns a future that will resolve
///     to a [`String`](https://doc.rust-lang.org/std/string/struct.String.html) that contains the response body.
///
/// # usage
///
/// instances of this struct are returned by invoking one of the
/// [`HttpClient::request`](struct.HttpClient.html#method.request)'s methods.
///
/// ```
/// use simplist::HttpClient;
/// use simplist::HttpMethod;
/// use simplist::HttpRequest;
///
/// let url      = "https://hinaria.com".parse()?;
/// let http     = HttpClient::new(...);
/// let request  = HttpRequest::with(url, HttpMethod::Get);
/// let response = await http.request(request)?;
/// let string   = await response.read_as_string();
///
/// println!("{:?}", string)
/// // => Ok("<!doctype html>\n<html lang=\"en\">\n<head>\n    <meta charset=\"utf-8\"> ...")
/// ```
#[derive(Debug)]
pub struct HttpResponse {
    underlying: Response,
}

impl HttpResponse {
    pub(crate) fn new(underlying: Response) -> HttpResponse {
        HttpResponse { underlying }
    }

    /// returns the http headers for this response.
    ///
    /// # examples
    ///
    /// ```
    /// use hyper::Headers;
    /// use simplist::HttpClient;
    /// use simplist::HttpMethod;
    /// use simplist::HttpRequest;
    ///
    /// let url      = "https://hinaria.com".parse()?;
    /// let http     = HttpClient::new(...);
    /// let request  = HttpRequest::with(url, HttpMethod::Get);
    /// let response = await http.request(request)?;
    /// let headers  = response.headers();
    ///
    /// assert_eq!(headers.has::<ContentType>(), true);
    /// ```
    pub fn headers(&self) -> &Headers {
        self.underlying.headers()
    }

    /// returns the status code for this response.
    ///
    /// # examples
    ///
    /// ```
    /// use hyper::status::StatusCode;
    /// use simplist::HttpClient;
    /// use simplist::HttpMethod;
    /// use simplist::HttpRequest;
    ///
    /// let url      = "https://hinaria.com".parse()?;
    /// let http     = HttpClient::new(...);
    /// let request  = HttpRequest::with(url, HttpMethod::Get);
    /// let response = await http.request(request)?;
    ///
    /// assert_eq!(response.status(), StatusCode::Ok);
    /// ```
    pub fn status(&self) -> StatusCode {
        self.underlying.status()
    }

    /// returns the status code for as a `u16`.
    ///
    /// # examples
    ///
    /// ```
    /// use simplist::HttpClient;
    /// use simplist::HttpMethod;
    /// use simplist::HttpRequest;
    ///
    /// let url      = "https://hinaria.com".parse()?;
    /// let http     = HttpClient::new(...);
    /// let request  = HttpRequest::with(url, HttpMethod::Get);
    /// let response = await http.request(request)?;
    ///
    /// assert_eq!(response.status_code(), 200);
    /// ```
    pub fn status_code(&self) -> u16 {
        self.underlying.status().into()
    }

    /// reads this response, returning a [`Vec<u8>`](https://doc.rust-lang.org/std/vec/struct.Vec.html).
    ///
    /// # examples
    ///
    /// ```
    /// use simplist::HttpClient;
    /// use simplist::HttpMethod;
    /// use simplist::HttpRequest;
    ///
    /// let url      = "https://hinaria.com".parse()?;
    /// let http     = HttpClient::new(...);
    /// let request  = HttpRequest::with(url, HttpMethod::Get);
    /// let response = await http.request(request)?;
    /// let data     = await response.read_as_bytes();
    ///
    /// println!("{:?}", data)
    /// // => Ok([60, 33, 68, 79, 67, 84, 89, 80, 69, 32, 104, 116, ...])
    /// ```
    pub fn read_as_bytes(self) -> Box<Future<Item = Vec<u8>, Error = HttpError>> {
        const READ_DEFAULT_CAPACITY:     usize = 10 * 1024;        // 10 kib
        const READ_MAX_INITIAL_CAPACITY: usize = 10 * 1024 * 1024; // 10 mib


        let capacity = self.underlying.headers()
            .get::<ContentLength>()
            .map      (|x| std::cmp::max(x.0 as usize, READ_MAX_INITIAL_CAPACITY))
            .unwrap_or(READ_DEFAULT_CAPACITY);

        let future = self.underlying.body().fold(
            Vec::with_capacity(capacity),
            |mut data, chunk| { data.extend(chunk); hina::task::completed::<_, HyperError>(data) }
        ).map_err(From::from);

        Box::new(future)
    }

    /// reads this response, returning a [`String`](https://doc.rust-lang.org/std/string/struct.String.html).
    ///
    /// # examples
    ///
    /// ```
    /// use simplist::HttpClient;
    /// use simplist::HttpMethod;
    /// use simplist::HttpRequest;
    ///
    /// let url      = "https://hinaria.com".parse()?;
    /// let http     = HttpClient::new(...);
    /// let request  = HttpRequest::with(url, HttpMethod::Get);
    /// let response = await http.request(request)?;
    /// let string   = await response.read_as_string();
    ///
    /// println!("{:?}", string)
    /// // => Ok("<!doctype html>\n<html lang=\"en\">\n<head>\n    <meta charset=\"utf-8\"> ...")
    /// ```
    pub fn read_as_string(self) -> Box<Future<Item = String, Error = HttpError>> {
        let future = self
            .read_as_bytes()
            .and_then     (|x| String::from_utf8(x).map_err(From::from));

        Box::new(future)
    }
}





/// a http response, whose body can be read synchronously.
///
/// there are two primary methods to retrieve the body for a response:
///
///   - [`fn read_as_bytes(...)`](struct.HttpSyncResponse.html#method.read_as_bytes): returns a [`Result<Vec<u8>,
///     HttpError>`](https://doc.rust-lang.org/std/vec/struct.Vec.html) that contains the response body.
///   - [`fn read_as_string(...)`](struct.HttpSyncResponse.html#method.read_as_string): returns a [`Result<String,
///     HttpError>`](https://doc.rust-lang.org/std/string/struct.String.html) that contains the response
///     body.
///
/// # usage
///
/// instances of this struct are returned by invoking one of the
/// [`HttpSyncClient::request`](struct.HttpSyncClient.html#method.request)'s methods.
///
/// ```
/// use simplist::HttpMethod;
/// use simplist::HttpResponse;
/// use simplist::HttpSyncClient;
///
/// let url      = "https://hinaria.com".parse()?;
/// let http     = HttpSyncClient::new(...);
/// let request  = HttpRequest::with(url, HttpMethod::Get);
/// let response = http.request(request)?;
/// let string   = response.read_as_string();
///
/// println!("{:?}", string)
/// // => Ok("<!doctype html>\n<html lang=\"en\">\n<head>\n    <meta charset=\"utf-8\"> ...")
/// ```
#[derive(Debug)]
pub struct HttpSyncResponse {
    underlying: HttpResponse,
}

impl HttpSyncResponse {
    pub(crate) fn new(underlying: HttpResponse) -> HttpSyncResponse {
        HttpSyncResponse { underlying }
    }

    /// returns the http headers for this response.
    ///
    /// # examples
    ///
    /// ```
    /// use hyper::Headers;
    /// use simplist::HttpSyncClient;
    /// use simplist::HttpMethod;
    /// use simplist::HttpRequest;
    ///
    /// let url      = "https://hinaria.com".parse()?;
    /// let http     = HttpSyncClient::new(...);
    /// let request  = HttpRequest::with(url, HttpMethod::Get);
    /// let response = await http.request(request)?;
    /// let headers  = response.headers();
    ///
    /// assert_eq!(headers.has::<ContentType>(), true);
    /// ```
    pub fn headers(&self) -> &Headers {
        self.underlying.headers()
    }

    /// returns the status code for this response.
    ///
    /// # examples
    ///
    /// ```
    /// use hyper::status::StatusCode;
    /// use simplist::HttpMethod;
    /// use simplist::HttpRequest;
    /// use simplist::HttpSyncClient;
    ///
    /// let url      = "https://hinaria.com".parse()?;
    /// let http     = HttpSyncClient::new(...);
    /// let request  = HttpRequest::with(url, HttpMethod::Get);
    /// let response = http.request(request)?;
    ///
    /// assert_eq!(response.status(), StatusCode::Ok);
    /// ```
    pub fn status(&self) -> StatusCode {
        self.underlying.status()
    }

    /// returns the status code for as a `u16`.
    ///
    /// # examples
    ///
    /// ```
    /// use simplist::HttpMethod;
    /// use simplist::HttpRequest;
    /// use simplist::HttpSyncClient;
    ///
    /// let url      = "https://hinaria.com".parse()?;
    /// let http     = HttpSyncClient::new(...);
    /// let request  = HttpRequest::with(url, HttpMethod::Get);
    /// let response = http.request(request)?;
    ///
    /// assert_eq!(response.status_code(), 200);
    /// ```
    pub fn status_code(&self) -> u16 {
        self.underlying.status_code()
    }

    /// reads this response, returning a [`Vec<u8>`](https://doc.rust-lang.org/std/vec/struct.Vec.html).
    ///
    /// # examples
    ///
    /// ```
    /// use simplist::HttpMethod;
    /// use simplist::HttpRequest;
    /// use simplist::HttpSyncClient;
    ///
    /// let url      = "https://hinaria.com".parse()?;
    /// let http     = HttpSyncClient::new(...);
    /// let request  = HttpRequest::with(url, HttpMethod::Get);
    /// let response = http.request(request)?;
    /// let data     = await response.read_as_bytes();
    ///
    /// println!("{:?}", data)
    /// // => Ok([60, 33, 68, 79, 67, 84, 89, 80, 69, 32, 104, 116, ...])
    /// ```
    pub fn read_as_bytes(self) -> Result<Vec<u8>, HttpError> {
        self.underlying.read_as_bytes().wait()
    }

    /// reads this response, returning a [`String`](https://doc.rust-lang.org/std/string/struct.String.html).
    ///
    /// # examples
    ///
    /// ```
    /// use simplist::HttpMethod;
    /// use simplist::HttpRequest;
    /// use simplist::HttpSyncClient;
    ///
    /// let url      = "https://hinaria.com".parse()?;
    /// let http     = HttpSyncClient::new(...);
    /// let request  = HttpRequest::with(url, HttpMethod::Get);
    /// let response = http.request(request)?;
    /// let string   = response.read_as_string();
    ///
    /// println!("{:?}", string)
    /// // => Ok("<!doctype html>\n<html lang=\"en\">\n<head>\n    <meta charset=\"utf-8\"> ...")
    /// ```
    pub fn read_as_string(self) -> Result<String, HttpError> {
        self.underlying.read_as_string().wait()
    }
}