use std::rc::Rc; use std::net::SocketAddr; use actix::dev::*; use bytes::Bytes; use futures::{Future, Poll, Async}; use tokio_io::{AsyncRead, AsyncWrite}; use h1; use h2; use pipeline::Pipeline; use httprequest::HttpRequest; /// Low level http request handler pub trait HttpHandler: 'static { /// Handle request fn handle(&self, req: HttpRequest) -> Result; } /// Conversion helper trait pub trait IntoHttpHandler { /// The associated type which is result of conversion. type Handler: HttpHandler; /// Convert into `HttpHandler` object. fn into_handler(self) -> Self::Handler; } impl IntoHttpHandler for T { type Handler = T; fn into_handler(self) -> Self::Handler { self } } enum HttpProtocol where T: AsyncRead + AsyncWrite + 'static, H: 'static { H1(h1::Http1), H2(h2::Http2), } #[doc(hidden)] pub struct HttpChannel where T: AsyncRead + AsyncWrite + 'static, H: 'static { proto: Option>, } impl HttpChannel where T: AsyncRead + AsyncWrite + 'static, H: HttpHandler + 'static { pub fn new(stream: T, local: SocketAddr, secure: bool, peer: Option, router: Rc>, http2: bool) -> HttpChannel { if http2 { HttpChannel { proto: Some(HttpProtocol::H2( h2::Http2::new(stream, local, secure, peer, router, Bytes::new()))) } } else { HttpChannel { proto: Some(HttpProtocol::H1( h1::Http1::new(stream, local, secure, peer, router))) } } } } /*impl Drop for HttpChannel { fn drop(&mut self) { println!("Drop http channel"); } }*/ impl Actor for HttpChannel where T: AsyncRead + AsyncWrite + 'static, H: HttpHandler + 'static { type Context = Context; } impl Future for HttpChannel where T: AsyncRead + AsyncWrite + 'static, H: HttpHandler + 'static { type Item = (); type Error = (); fn poll(&mut self) -> Poll { match self.proto { Some(HttpProtocol::H1(ref mut h1)) => { match h1.poll() { Ok(Async::Ready(h1::Http1Result::Done)) => return Ok(Async::Ready(())), Ok(Async::Ready(h1::Http1Result::Switch)) => (), Ok(Async::NotReady) => return Ok(Async::NotReady), Err(_) => return Err(()), } } Some(HttpProtocol::H2(ref mut h2)) => return h2.poll(), None => unreachable!(), } // upgrade to h2 let proto = self.proto.take().unwrap(); match proto { HttpProtocol::H1(h1) => { let (stream, local, secure, addr, router, buf) = h1.into_inner(); self.proto = Some(HttpProtocol::H2( h2::Http2::new(stream, local, secure, addr, router, buf))); self.poll() } _ => unreachable!() } } }