use std::io::{self, Read};
use std::net::SocketAddr;
use std::fmt::{self, Debug};
use hyper::uri::RequestUri::{AbsoluteUri, AbsolutePath};
use hyper::net::NetworkStream;
use hyper::http::h1::HttpReader;
use hyper::version::HttpVersion;
use typemap::TypeMap;
use plugin::Extensible;
use method::Method;
pub use hyper::server::request::Request as HttpRequest;
use hyper::buffer;
#[cfg(test)]
use std::net::ToSocketAddrs;
pub use self::url::Url;
use {Protocol, Plugin, Headers, Set, headers};
mod url;
pub struct Request<'a, 'b: 'a> {
pub url: Url,
pub remote_addr: SocketAddr,
pub local_addr: SocketAddr,
pub headers: Headers,
pub body: Body<'a, 'b>,
pub method: Method,
pub extensions: TypeMap,
pub version: HttpVersion,
_p: (),
}
impl<'a, 'b> Debug for Request<'a, 'b> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
try!(writeln!(f, "Request {{"));
try!(writeln!(f, " url: {:?}", self.url));
try!(writeln!(f, " method: {:?}", self.method));
try!(writeln!(f, " remote_addr: {:?}", self.remote_addr));
try!(writeln!(f, " local_addr: {:?}", self.local_addr));
try!(write!(f, "}}"));
Ok(())
}
}
impl<'a, 'b> Request<'a, 'b> {
pub fn from_http(req: HttpRequest<'a, 'b>, local_addr: SocketAddr, protocol: &Protocol)
-> Result<Request<'a, 'b>, String> {
let (addr, method, headers, uri, version, reader) = req.deconstruct();
let url = match uri {
AbsoluteUri(ref url) => {
match Url::from_generic_url(url.clone()) {
Ok(url) => url,
Err(e) => return Err(e)
}
},
AbsolutePath(ref path) => {
let url_string = match (version, headers.get::<headers::Host>()) {
(_, Some(host)) => {
if let Some(port) = host.port {
format!("{}://{}:{}{}", protocol.name(), host.hostname, port, path)
} else {
format!("{}://{}{}", protocol.name(), host.hostname, path)
}
},
(v, None) if v < HttpVersion::Http11 => {
match local_addr {
SocketAddr::V4(addr4) => format!("{}://{}:{}{}", protocol.name(), addr4.ip(), local_addr.port(), path),
SocketAddr::V6(addr6) => format!("{}://[{}]:{}{}", protocol.name(), addr6.ip(), local_addr.port(), path),
}
},
(_, None) => {
return Err("No host specified in request".into())
}
};
match Url::parse(&url_string) {
Ok(url) => url,
Err(e) => return Err(format!("Couldn't parse requested URL: {}", e))
}
},
_ => return Err("Unsupported request URI".into())
};
Ok(Request {
url: url,
remote_addr: addr,
local_addr: local_addr,
headers: headers,
body: Body::new(reader),
method: method,
extensions: TypeMap::new(),
version: version,
_p: (),
})
}
#[cfg(test)]
pub fn stub() -> Request<'a, 'b> {
Request {
url: Url::parse("http://www.rust-lang.org").unwrap(),
remote_addr: "localhost:3000".to_socket_addrs().unwrap().next().unwrap(),
local_addr: "localhost:3000".to_socket_addrs().unwrap().next().unwrap(),
headers: Headers::new(),
body: unsafe { ::std::mem::uninitialized() },
method: Method::Get,
extensions: TypeMap::new(),
version: HttpVersion::Http11,
_p: (),
}
}
}
pub struct Body<'a, 'b: 'a>(HttpReader<&'a mut buffer::BufReader<&'b mut NetworkStream>>);
impl<'a, 'b> Body<'a, 'b> {
pub fn new(reader: HttpReader<&'a mut buffer::BufReader<&'b mut NetworkStream>>) -> Body<'a, 'b> {
Body(reader)
}
}
impl<'a, 'b> Read for Body<'a, 'b> {
fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
self.0.read(buf)
}
}
impl<'a, 'b> Extensible for Request<'a, 'b> {
fn extensions(&self) -> &TypeMap {
&self.extensions
}
fn extensions_mut(&mut self) -> &mut TypeMap {
&mut self.extensions
}
}
impl<'a, 'b> Plugin for Request<'a, 'b> {}
impl<'a, 'b> Set for Request<'a, 'b> {}