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
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
//! Defines the `HttpMessage` trait that serves to encapsulate the operations of a single
//! request-response cycle on any HTTP connection.

use std::any::{Any, TypeId};
use std::fmt::Debug;
use std::io::{Read, Write};
use std::mem;

#[cfg(feature = "timeouts")]
use std::io;
#[cfg(feature = "timeouts")]
use std::time::Duration;

use typeable::Typeable;

use header::Headers;
use http::RawStatus;
use url::Url;

use method;
use version;
use traitobject;

/// The trait provides an API for creating new `HttpMessage`s depending on the underlying HTTP
/// protocol.
pub trait Protocol {
    /// Creates a fresh `HttpMessage` bound to the given host, based on the given protocol scheme.
    fn new_message(&self, host: &str, port: u16, scheme: &str) -> ::Result<Box<HttpMessage>>;
}

/// Describes a request.
#[derive(Clone, Debug)]
pub struct RequestHead {
    /// The headers of the request
    pub headers: Headers,
    /// The method of the request
    pub method: method::Method,
    /// The URL of the request
    pub url: Url,
}

/// Describes a response.
#[derive(Clone, Debug)]
pub struct ResponseHead {
    /// The headers of the reponse
    pub headers: Headers,
    /// The raw status line of the response
    pub raw_status: RawStatus,
    /// The HTTP/2 version which generated the response
    pub version: version::HttpVersion,
}

/// The trait provides an API for sending an receiving HTTP messages.
pub trait HttpMessage: Write + Read + Send + Any + Typeable + Debug {
    /// Initiates a new outgoing request.
    ///
    /// Only the request's head is provided (in terms of the `RequestHead` struct).
    ///
    /// After this, the `HttpMessage` instance can be used as an `io::Write` in order to write the
    /// body of the request.
    fn set_outgoing(&mut self, head: RequestHead) -> ::Result<RequestHead>;
    /// Obtains the incoming response and returns its head (i.e. the `ResponseHead` struct)
    ///
    /// After this, the `HttpMessage` instance can be used as an `io::Read` in order to read out
    /// the response body.
    fn get_incoming(&mut self) -> ::Result<ResponseHead>;
    /// Set the read timeout duration for this message.
    #[cfg(feature = "timeouts")]
    fn set_read_timeout(&self, dur: Option<Duration>) -> io::Result<()>;
    /// Set the write timeout duration for this message.
    #[cfg(feature = "timeouts")]
    fn set_write_timeout(&self, dur: Option<Duration>) -> io::Result<()>;
    /// Closes the underlying HTTP connection.
    fn close_connection(&mut self) -> ::Result<()>;
    /// Returns whether the incoming message has a body.
    fn has_body(&self) -> bool;
}

impl HttpMessage {
    unsafe fn downcast_ref_unchecked<T: 'static>(&self) -> &T {
        mem::transmute(traitobject::data(self))
    }

    unsafe fn downcast_mut_unchecked<T: 'static>(&mut self) -> &mut T {
        mem::transmute(traitobject::data_mut(self))
    }

    unsafe fn downcast_unchecked<T: 'static>(self: Box<HttpMessage>) -> Box<T>  {
        let raw: *mut HttpMessage = mem::transmute(self);
        mem::transmute(traitobject::data_mut(raw))
    }
}

impl HttpMessage {
    /// Is the underlying type in this trait object a T?
    #[inline]
    pub fn is<T: Any>(&self) -> bool {
        (*self).get_type() == TypeId::of::<T>()
    }

    /// If the underlying type is T, get a reference to the contained data.
    #[inline]
    pub fn downcast_ref<T: Any>(&self) -> Option<&T> {
        if self.is::<T>() {
            Some(unsafe { self.downcast_ref_unchecked() })
        } else {
            None
        }
    }

    /// If the underlying type is T, get a mutable reference to the contained
    /// data.
    #[inline]
    pub fn downcast_mut<T: Any>(&mut self) -> Option<&mut T> {
        if self.is::<T>() {
            Some(unsafe { self.downcast_mut_unchecked() })
        } else {
            None
        }
    }

    /// If the underlying type is T, extract it.
    #[inline]
    pub fn downcast<T: Any>(self: Box<HttpMessage>)
            -> Result<Box<T>, Box<HttpMessage>> {
        if self.is::<T>() {
            Ok(unsafe { self.downcast_unchecked() })
        } else {
            Err(self)
        }
    }
}