use std::net::{ToSocketAddrs, SocketAddr};
use std::time::Duration;
#[cfg(feature = "ssl")]
use std::path::PathBuf;
pub use hyper::server::Listening;
use hyper::server::Server;
use hyper::net::Fresh;
use request::HttpRequest;
use response::HttpResponse;
use error::HttpResult;
use {Request, Handler};
use status;
pub struct Iron<H> {
pub handler: H,
addr: Option<SocketAddr>,
protocol: Option<Protocol>
}
#[derive(Debug, PartialEq, Clone, Copy)]
pub struct Timeouts {
pub keep_alive: Option<Duration>,
pub read: Option<Duration>,
pub write: Option<Duration>
}
impl Default for Timeouts {
fn default() -> Self {
Timeouts {
keep_alive: Some(Duration::from_secs(5)),
read: Some(Duration::from_secs(30)),
write: Some(Duration::from_secs(1))
}
}
}
#[derive(Clone)]
pub enum Protocol {
Http,
#[cfg(feature = "ssl")]
Https {
certificate: PathBuf,
key: PathBuf
}
}
impl Protocol {
pub fn name(&self) -> &'static str {
match *self {
Protocol::Http => "http",
#[cfg(feature = "ssl")]
Protocol::Https { .. } => "https"
}
}
}
impl<H: Handler> Iron<H> {
pub fn http<A: ToSocketAddrs>(self, addr: A) -> HttpResult<Listening> {
self.listen_with(addr, 8 * ::num_cpus::get(), Protocol::Http, None)
}
#[cfg(feature = "ssl")]
pub fn https<A: ToSocketAddrs>(self, addr: A, certificate: PathBuf, key: PathBuf)
-> HttpResult<Listening> {
self.listen_with(addr, 8 * ::num_cpus::get(),
Protocol::Https { certificate: certificate, key: key }, None)
}
pub fn listen_with<A: ToSocketAddrs>(mut self, addr: A, threads: usize,
protocol: Protocol,
timeouts: Option<Timeouts>) -> HttpResult<Listening> {
let sock_addr = addr.to_socket_addrs()
.ok().and_then(|mut addrs| addrs.next()).expect("Could not parse socket address.");
self.addr = Some(sock_addr);
self.protocol = Some(protocol.clone());
match protocol {
Protocol::Http => {
let mut server = try!(Server::http(sock_addr));
let timeouts = timeouts.unwrap_or_default();
server.keep_alive(timeouts.keep_alive);
server.set_read_timeout(timeouts.read);
server.set_write_timeout(timeouts.write);
server.handle_threads(self, threads)
},
#[cfg(feature = "ssl")]
Protocol::Https { ref certificate, ref key } => {
use hyper::net::Openssl;
let ssl = try!(Openssl::with_cert_and_key(certificate, key));
let mut server = try!(Server::https(sock_addr, ssl));
let timeouts = timeouts.unwrap_or_default();
server.keep_alive(timeouts.keep_alive);
server.set_read_timeout(timeouts.read);
server.set_write_timeout(timeouts.write);
server.handle_threads(self, threads)
}
}
}
pub fn new(handler: H) -> Iron<H> {
Iron { handler: handler, addr: None, protocol: None }
}
}
impl<H: Handler> ::hyper::server::Handler for Iron<H> {
fn handle(&self, http_req: HttpRequest, mut http_res: HttpResponse<Fresh>) {
*http_res.status_mut() = status::InternalServerError;
match Request::from_http(http_req, self.addr.clone().unwrap(),
self.protocol.as_ref().unwrap()) {
Ok(mut req) => {
self.handler.handle(&mut req).unwrap_or_else(|e| {
error!("Error handling:\n{:?}\nError was: {:?}", req, e.error);
e.response
}).write_back(http_res)
},
Err(e) => {
error!("Error creating request:\n {}", e);
bad_request(http_res)
}
}
}
}
fn bad_request(mut http_res: HttpResponse<Fresh>) {
*http_res.status_mut() = status::BadRequest;
if let Ok(res) = http_res.start()
{
let _ = res.end();
}
}