1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
//! Simple to use wrappers for dealing with fully buffered requests
//!
//! By "fully buffered" I mean two things:
//!
//! * No request or response streaming
//! * All headers and body are allocated on the heap
//!
//! Raw interface allows more granular control to make things more efficient,
//! but requires more boilerplate. You can mix and match different
//! styles on single HTTP connection.
//!
use url::Url;
use futures::Async;
use futures::future::{FutureResult, ok};
use futures::sync::oneshot::{channel, Sender, Receiver};

use enums::Status;
use enums::Version;
use client::{Error, Codec, Encoder, EncoderDone, Head, RecvMode};
use client::errors::ErrorEnum;

/// Fully buffered (in-memory) writing request and reading response
///
/// This coded should be used when you don't have any special needs
pub struct Buffered {
    method: &'static str,
    url: Url,
    sender: Option<Sender<Result<Response, Error>>>,
    response: Option<Response>,
    max_response_length: usize,
}

#[derive(Debug)]
/// A buffered response holds contains a body as contiguous chunk of data
pub struct Response {
    status: Status,
    headers: Vec<(String, Vec<u8>)>,
    body: Vec<u8>,
}

impl Response {
    /// Get response status
    pub fn status(&self) -> Status {
        self.status
    }
    /// Get response headers
    pub fn headers(&self) -> &[(String, Vec<u8>)] {
        &self.headers
    }
    /// Get response body
    pub fn body(&self) -> &[u8] {
        &self.body
    }
}

impl<S> Codec<S> for Buffered {
    type Future = FutureResult<EncoderDone<S>, Error>;
    fn start_write(&mut self, mut e: Encoder<S>) -> Self::Future {
        e.request_line(self.method, self.url.path(), Version::Http11);
        self.url.host_str().map(|x| {
            e.add_header("Host", x).unwrap();
        });
        e.done_headers().unwrap();
        ok(e.done())
    }
    fn headers_received(&mut self, headers: &Head) -> Result<RecvMode, Error> {
        let status = headers.status()
            .ok_or(ErrorEnum::InvalidStatus)?;
        self.response = Some(Response {
            status: status,
            headers: headers.headers().map(|(k, v)| {
                (k.to_string(), v.to_vec())
            }).collect(),
            body: Vec::new(),
        });
        Ok(RecvMode::buffered(self.max_response_length))
    }
    fn data_received(&mut self, data: &[u8], end: bool)
        -> Result<Async<usize>, Error>
    {
        assert!(end);
        let mut response = self.response.take().unwrap();
        response.body = data.to_vec();
        self.sender.take().unwrap().send(Ok(response))
            .map_err(|_| debug!("Unused HTTP response")).ok();
        Ok(Async::Ready(data.len()))
    }
}

impl Buffered {
    /// Fetch data from url using GET method, fully buffered
    pub fn get(url: Url) -> (Buffered, Receiver<Result<Response, Error>>) {
        let (tx, rx) = channel();
        (Buffered {
                method: "GET",
                url: url,
                sender: Some(tx),
                max_response_length: 10_485_760,
                response: None,
            },
         rx)
    }
    /// Set max response length for this buffered reader
    pub fn max_response_length(&mut self, value: usize) {
        self.max_response_length = value;
    }
}