hyper_sync/http/
message.rs

1//! Defines the `HttpMessage` trait that serves to encapsulate the operations of a single
2//! request-response cycle on any HTTP connection.
3
4use std::any::{Any, TypeId};
5use std::fmt::Debug;
6use std::io::{Read, Write};
7use std::mem;
8
9use std::io;
10use std::time::Duration;
11
12use header::Headers;
13use http::RawStatus;
14use url::Url;
15
16use method;
17use version;
18
19/// The trait provides an API for creating new `HttpMessage`s depending on the underlying HTTP
20/// protocol.
21pub trait Protocol {
22    /// Creates a fresh `HttpMessage` bound to the given host, based on the given protocol scheme.
23    fn new_message(&self, host: &str, port: u16, scheme: &str) -> ::Result<Box<HttpMessage>>;
24}
25
26/// Describes a request.
27#[derive(Clone, Debug)]
28pub struct RequestHead {
29    /// The headers of the request
30    pub headers: Headers,
31    /// The method of the request
32    pub method: method::Method,
33    /// The URL of the request
34    pub url: Url,
35}
36
37/// Describes a response.
38#[derive(Clone, Debug)]
39pub struct ResponseHead {
40    /// The headers of the reponse
41    pub headers: Headers,
42    /// The raw status line of the response
43    pub raw_status: RawStatus,
44    /// The HTTP/2 version which generated the response
45    pub version: version::HttpVersion,
46}
47
48/// The trait provides an API for sending an receiving HTTP messages.
49pub trait HttpMessage: Write + Read + Send + Any + ::GetType + Debug {
50    /// Initiates a new outgoing request.
51    ///
52    /// Only the request's head is provided (in terms of the `RequestHead` struct).
53    ///
54    /// After this, the `HttpMessage` instance can be used as an `io::Write` in order to write the
55    /// body of the request.
56    fn set_outgoing(&mut self, head: RequestHead) -> ::Result<RequestHead>;
57    /// Obtains the incoming response and returns its head (i.e. the `ResponseHead` struct)
58    ///
59    /// After this, the `HttpMessage` instance can be used as an `io::Read` in order to read out
60    /// the response body.
61    fn get_incoming(&mut self) -> ::Result<ResponseHead>;
62    /// Set the read timeout duration for this message.
63    fn set_read_timeout(&self, dur: Option<Duration>) -> io::Result<()>;
64    /// Set the write timeout duration for this message.
65    fn set_write_timeout(&self, dur: Option<Duration>) -> io::Result<()>;
66    /// Closes the underlying HTTP connection.
67    fn close_connection(&mut self) -> ::Result<()>;
68    /// Returns whether the incoming message has a body.
69    fn has_body(&self) -> bool;
70    /// Called when the Client wishes to use a Proxy.
71    fn set_proxied(&mut self, val: bool) {
72        // default implementation so as to not be a breaking change.
73        warn!("default set_proxied({:?})", val);
74    }
75}
76
77impl HttpMessage {
78    unsafe fn downcast_ref_unchecked<T: 'static>(&self) -> &T {
79        &*(mem::transmute::<*const _, (*const (), *const ())>(self).0 as *const T)
80    }
81
82    unsafe fn downcast_mut_unchecked<T: 'static>(&mut self) -> &mut T {
83        &mut *(mem::transmute::<*mut _, (*mut (), *mut ())>(self).0 as *mut T)
84    }
85
86    unsafe fn downcast_unchecked<T: 'static>(self: Box<HttpMessage>) -> Box<T>  {
87        Box::from_raw(mem::transmute::<*mut _, (*mut (), *mut ())>(Box::into_raw(self)).0 as *mut T)
88    }
89}
90
91impl HttpMessage {
92    /// Is the underlying type in this trait object a T?
93    #[inline]
94    pub fn is<T: Any>(&self) -> bool {
95        (*self).get_type() == TypeId::of::<T>()
96    }
97
98    /// If the underlying type is T, get a reference to the contained data.
99    #[inline]
100    pub fn downcast_ref<T: Any>(&self) -> Option<&T> {
101        if self.is::<T>() {
102            Some(unsafe { self.downcast_ref_unchecked() })
103        } else {
104            None
105        }
106    }
107
108    /// If the underlying type is T, get a mutable reference to the contained
109    /// data.
110    #[inline]
111    pub fn downcast_mut<T: Any>(&mut self) -> Option<&mut T> {
112        if self.is::<T>() {
113            Some(unsafe { self.downcast_mut_unchecked() })
114        } else {
115            None
116        }
117    }
118
119    /// If the underlying type is T, extract it.
120    #[inline]
121    pub fn downcast<T: Any>(self: Box<HttpMessage>)
122            -> Result<Box<T>, Box<HttpMessage>> {
123        if self.is::<T>() {
124            Ok(unsafe { self.downcast_unchecked() })
125        } else {
126            Err(self)
127        }
128    }
129}