diff --git a/src/lib.rs b/src/lib.rs index 595a33afd7..ba0a97f973 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -185,6 +185,7 @@ pub mod server; pub mod status; pub mod uri; pub mod version; +pub mod message; /// Re-exporting the mime crate, for convenience. diff --git a/src/message.rs b/src/message.rs new file mode 100644 index 0000000000..740075fe3c --- /dev/null +++ b/src/message.rs @@ -0,0 +1,114 @@ +//! Defines the `HttpMessage` trait that serves to encapsulate the operations of a single +//! request-response cycle on any HTTP connection. + +use std::fmt::Debug; +use std::any::{Any, TypeId}; +use std::io::{Read, Write}; + +use std::mem; + +use typeable::Typeable; + +use header::Headers; +use http::RawStatus; +use url::Url; + +use method; +use version; +use traitobject; + +/// 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; + /// 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; + + /// Closes the underlying HTTP connection. + fn close_connection(&mut self) -> ::Result<()>; +} + +impl HttpMessage { + unsafe fn downcast_ref_unchecked(&self) -> &T { + mem::transmute(traitobject::data(self)) + } + + unsafe fn downcast_mut_unchecked(&mut self) -> &mut T { + mem::transmute(traitobject::data_mut(self)) + } + + unsafe fn downcast_unchecked(self: Box) -> Box { + 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(&self) -> bool { + (*self).get_type() == TypeId::of::() + } + + /// If the underlying type is T, get a reference to the contained data. + #[inline] + pub fn downcast_ref(&self) -> Option<&T> { + if self.is::() { + 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(&mut self) -> Option<&mut T> { + if self.is::() { + Some(unsafe { self.downcast_mut_unchecked() }) + } else { + None + } + } + + /// If the underlying type is T, extract it. + #[inline] + pub fn downcast(self: Box) + -> Result, Box> { + if self.is::() { + Ok(unsafe { self.downcast_unchecked() }) + } else { + Err(self) + } + } +}