use std::fmt::Debug; use std::marker::PhantomData; use std::{io, net, rc}; use actix_codec::{AsyncRead, AsyncWrite, Framed}; use actix_server_config::{Io, IoStream, ServerConfig as SrvConfig}; use actix_service::{IntoNewService, NewService, Service}; use actix_utils::cloneable::CloneableService; use bytes::Bytes; use futures::future::{ok, FutureResult}; use futures::{try_ready, Async, Future, IntoFuture, Poll, Stream}; use h2::server::{self, Connection, Handshake}; use h2::RecvStream; use log::error; use crate::body::MessageBody; use crate::config::{KeepAlive, ServiceConfig}; use crate::error::{DispatchError, Error, ParseError, ResponseError}; use crate::helpers::DataFactory; use crate::payload::Payload; use crate::request::Request; use crate::response::Response; use super::dispatcher::Dispatcher; /// `NewService` implementation for HTTP2 transport pub struct H2Service { srv: S, cfg: ServiceConfig, on_connect: Option Box>>, _t: PhantomData<(T, P, B)>, } impl H2Service where S: NewService, S::Error: Into, S::Response: Into>, ::Future: 'static, B: MessageBody + 'static, { /// Create new `HttpService` instance. pub fn new>(service: F) -> Self { let cfg = ServiceConfig::new(KeepAlive::Timeout(5), 5000, 0); H2Service { cfg, on_connect: None, srv: service.into_new_service(), _t: PhantomData, } } /// Create new `HttpService` instance with config. pub fn with_config>(cfg: ServiceConfig, service: F) -> Self { H2Service { cfg, on_connect: None, srv: service.into_new_service(), _t: PhantomData, } } /// Set on connect callback. pub(crate) fn on_connect( mut self, f: Option Box>>, ) -> Self { self.on_connect = f; self } } impl NewService for H2Service where T: IoStream, S: NewService, S::Error: Into, S::Response: Into>, ::Future: 'static, B: MessageBody + 'static, { type Config = SrvConfig; type Request = Io; type Response = (); type Error = DispatchError; type InitError = S::InitError; type Service = H2ServiceHandler; type Future = H2ServiceResponse; fn new_service(&self, cfg: &SrvConfig) -> Self::Future { H2ServiceResponse { fut: self.srv.new_service(cfg).into_future(), cfg: Some(self.cfg.clone()), on_connect: self.on_connect.clone(), _t: PhantomData, } } } #[doc(hidden)] pub struct H2ServiceResponse { fut: ::Future, cfg: Option, on_connect: Option Box>>, _t: PhantomData<(T, P, B)>, } impl Future for H2ServiceResponse where T: IoStream, S: NewService, S::Error: Into, S::Response: Into>, ::Future: 'static, B: MessageBody + 'static, { type Item = H2ServiceHandler; type Error = S::InitError; fn poll(&mut self) -> Poll { let service = try_ready!(self.fut.poll()); Ok(Async::Ready(H2ServiceHandler::new( self.cfg.take().unwrap(), self.on_connect.clone(), service, ))) } } /// `Service` implementation for http/2 transport pub struct H2ServiceHandler { srv: CloneableService, cfg: ServiceConfig, on_connect: Option Box>>, _t: PhantomData<(T, P, B)>, } impl H2ServiceHandler where S: Service, S::Error: Into, S::Future: 'static, S::Response: Into>, B: MessageBody + 'static, { fn new( cfg: ServiceConfig, on_connect: Option Box>>, srv: S, ) -> H2ServiceHandler { H2ServiceHandler { cfg, on_connect, srv: CloneableService::new(srv), _t: PhantomData, } } } impl Service for H2ServiceHandler where T: IoStream, S: Service, S::Error: Into, S::Future: 'static, S::Response: Into>, B: MessageBody + 'static, { type Request = Io; type Response = (); type Error = DispatchError; type Future = H2ServiceHandlerResponse; fn poll_ready(&mut self) -> Poll<(), Self::Error> { self.srv.poll_ready().map_err(|e| { let e = e.into(); error!("Service readiness error: {:?}", e); DispatchError::Service(e) }) } fn call(&mut self, req: Self::Request) -> Self::Future { let io = req.into_parts().0; let peer_addr = io.peer_addr(); let on_connect = if let Some(ref on_connect) = self.on_connect { Some(on_connect(&io)) } else { None }; H2ServiceHandlerResponse { state: State::Handshake( Some(self.srv.clone()), Some(self.cfg.clone()), peer_addr, on_connect, server::handshake(io), ), } } } enum State, B: MessageBody> where S::Future: 'static, { Incoming(Dispatcher), Handshake( Option>, Option, Option, Option>, Handshake, ), } pub struct H2ServiceHandlerResponse where T: IoStream, S: Service, S::Error: Into, S::Future: 'static, S::Response: Into>, B: MessageBody + 'static, { state: State, } impl Future for H2ServiceHandlerResponse where T: IoStream, S: Service, S::Error: Into, S::Future: 'static, S::Response: Into>, B: MessageBody, { type Item = (); type Error = DispatchError; fn poll(&mut self) -> Poll { match self.state { State::Incoming(ref mut disp) => disp.poll(), State::Handshake( ref mut srv, ref mut config, ref peer_addr, ref mut on_connect, ref mut handshake, ) => match handshake.poll() { Ok(Async::Ready(conn)) => { self.state = State::Incoming(Dispatcher::new( srv.take().unwrap(), conn, on_connect.take(), config.take().unwrap(), None, peer_addr.clone(), )); self.poll() } Ok(Async::NotReady) => Ok(Async::NotReady), Err(err) => { trace!("H2 handshake error: {}", err); Err(err.into()) } }, } } }