use std::marker::PhantomData; use std::{fmt, io}; use actix_codec::{AsyncRead, AsyncWrite, Framed}; use actix_server_config::{Io as ServerIo, Protocol, ServerConfig as SrvConfig}; use actix_service::{IntoNewService, NewService, Service}; use actix_utils::cloneable::CloneableService; use bytes::{Buf, BufMut, Bytes, BytesMut}; use futures::{try_ready, Async, Future, IntoFuture, Poll}; use h2::server::{self, Handshake}; use crate::body::MessageBody; use crate::builder::HttpServiceBuilder; use crate::config::{KeepAlive, ServiceConfig}; use crate::error::{DispatchError, Error}; use crate::request::Request; use crate::response::Response; use crate::{h1, h2::Dispatcher}; /// `NewService` HTTP1.1/HTTP2 transport implementation pub struct HttpService> { srv: S, cfg: ServiceConfig, expect: X, upgrade: Option, _t: PhantomData<(T, P, B)>, } impl HttpService where S: NewService, S::Error: Into, S::InitError: fmt::Debug, S::Response: Into>, ::Future: 'static, B: MessageBody + 'static, { /// Create builder for `HttpService` instance. pub fn build() -> HttpServiceBuilder { HttpServiceBuilder::new() } } impl HttpService where S: NewService, S::Error: Into, S::InitError: fmt::Debug, 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); HttpService { cfg, srv: service.into_new_service(), expect: h1::ExpectHandler, upgrade: None, _t: PhantomData, } } /// Create new `HttpService` instance with config. pub(crate) fn with_config>( cfg: ServiceConfig, service: F, ) -> Self { HttpService { cfg, srv: service.into_new_service(), expect: h1::ExpectHandler, upgrade: None, _t: PhantomData, } } } impl HttpService where S: NewService, S::Error: Into, S::InitError: fmt::Debug, S::Response: Into>, B: MessageBody, { /// Provide service for `EXPECT: 100-Continue` support. /// /// Service get called with request that contains `EXPECT` header. /// Service must return request in case of success, in that case /// request will be forwarded to main service. pub fn expect(self, expect: X1) -> HttpService where X1: NewService, X1::Error: Into, X1::InitError: fmt::Debug, { HttpService { expect, cfg: self.cfg, srv: self.srv, upgrade: self.upgrade, _t: PhantomData, } } /// Provide service for custom `Connection: UPGRADE` support. /// /// If service is provided then normal requests handling get halted /// and this service get called with original request and framed object. pub fn upgrade(self, upgrade: Option) -> HttpService where U1: NewService), Response = ()>, U1::Error: fmt::Display, U1::InitError: fmt::Debug, { HttpService { upgrade, cfg: self.cfg, srv: self.srv, expect: self.expect, _t: PhantomData, } } } impl NewService for HttpService where T: AsyncRead + AsyncWrite, S: NewService, S::Error: Into, S::InitError: fmt::Debug, S::Response: Into>, ::Future: 'static, B: MessageBody + 'static, X: NewService, X::Error: Into, X::InitError: fmt::Debug, U: NewService), Response = ()>, U::Error: fmt::Display, U::InitError: fmt::Debug, { type Request = ServerIo; type Response = (); type Error = DispatchError; type InitError = (); type Service = HttpServiceHandler; type Future = HttpServiceResponse; fn new_service(&self, cfg: &SrvConfig) -> Self::Future { HttpServiceResponse { fut: self.srv.new_service(cfg).into_future(), fut_ex: Some(self.expect.new_service(&())), fut_upg: self.upgrade.as_ref().map(|f| f.new_service(&())), expect: None, upgrade: None, cfg: Some(self.cfg.clone()), _t: PhantomData, } } } #[doc(hidden)] pub struct HttpServiceResponse< T, P, S: NewService, B, X: NewService, U: NewService, > { fut: S::Future, fut_ex: Option, fut_upg: Option, expect: Option, upgrade: Option, cfg: Option, _t: PhantomData<(T, P, B)>, } impl Future for HttpServiceResponse where T: AsyncRead + AsyncWrite, S: NewService, S::Error: Into, S::InitError: fmt::Debug, S::Response: Into>, ::Future: 'static, B: MessageBody + 'static, X: NewService, X::Error: Into, X::InitError: fmt::Debug, U: NewService), Response = ()>, U::Error: fmt::Display, U::InitError: fmt::Debug, { type Item = HttpServiceHandler; type Error = (); fn poll(&mut self) -> Poll { if let Some(ref mut fut) = self.fut_ex { let expect = try_ready!(fut .poll() .map_err(|e| log::error!("Init http service error: {:?}", e))); self.expect = Some(expect); self.fut_ex.take(); } if let Some(ref mut fut) = self.fut_upg { let upgrade = try_ready!(fut .poll() .map_err(|e| log::error!("Init http service error: {:?}", e))); self.upgrade = Some(upgrade); self.fut_ex.take(); } let service = try_ready!(self .fut .poll() .map_err(|e| log::error!("Init http service error: {:?}", e))); Ok(Async::Ready(HttpServiceHandler::new( self.cfg.take().unwrap(), service, self.expect.take().unwrap(), self.upgrade.take(), ))) } } /// `Service` implementation for http transport pub struct HttpServiceHandler { srv: CloneableService, expect: CloneableService, upgrade: Option>, cfg: ServiceConfig, _t: PhantomData<(T, P, B, X)>, } impl HttpServiceHandler where S: Service, S::Error: Into, S::Future: 'static, S::Response: Into>, B: MessageBody + 'static, X: Service, X::Error: Into, U: Service), Response = ()>, U::Error: fmt::Display, { fn new( cfg: ServiceConfig, srv: S, expect: X, upgrade: Option, ) -> HttpServiceHandler { HttpServiceHandler { cfg, srv: CloneableService::new(srv), expect: CloneableService::new(expect), upgrade: upgrade.map(|s| CloneableService::new(s)), _t: PhantomData, } } } impl Service for HttpServiceHandler where T: AsyncRead + AsyncWrite, S: Service, S::Error: Into, S::Future: 'static, S::Response: Into>, B: MessageBody + 'static, X: Service, X::Error: Into, U: Service), Response = ()>, U::Error: fmt::Display, { type Request = ServerIo; type Response = (); type Error = DispatchError; type Future = HttpServiceHandlerResponse; fn poll_ready(&mut self) -> Poll<(), Self::Error> { let ready = self .expect .poll_ready() .map_err(|e| { let e = e.into(); log::error!("Http service readiness error: {:?}", e); DispatchError::Service(e) })? .is_ready(); let ready = self .srv .poll_ready() .map_err(|e| { let e = e.into(); log::error!("Http service readiness error: {:?}", e); DispatchError::Service(e) })? .is_ready() && ready; if ready { Ok(Async::Ready(())) } else { Ok(Async::NotReady) } } fn call(&mut self, req: Self::Request) -> Self::Future { let (io, _, proto) = req.into_parts(); match proto { Protocol::Http2 => { let io = Io { inner: io, unread: None, }; HttpServiceHandlerResponse { state: State::Handshake(Some(( server::handshake(io), self.cfg.clone(), self.srv.clone(), ))), } } Protocol::Http10 | Protocol::Http11 => HttpServiceHandlerResponse { state: State::H1(h1::Dispatcher::new( io, self.cfg.clone(), self.srv.clone(), self.expect.clone(), self.upgrade.clone(), )), }, _ => HttpServiceHandlerResponse { state: State::Unknown(Some(( io, BytesMut::with_capacity(14), self.cfg.clone(), self.srv.clone(), self.expect.clone(), self.upgrade.clone(), ))), }, } } } enum State where S: Service, S::Future: 'static, S::Error: Into, T: AsyncRead + AsyncWrite, B: MessageBody, X: Service, X::Error: Into, U: Service), Response = ()>, U::Error: fmt::Display, { H1(h1::Dispatcher), H2(Dispatcher, S, B>), Unknown( Option<( T, BytesMut, ServiceConfig, CloneableService, CloneableService, Option>, )>, ), Handshake(Option<(Handshake, Bytes>, ServiceConfig, CloneableService)>), } pub struct HttpServiceHandlerResponse where T: AsyncRead + AsyncWrite, S: Service, S::Error: Into, S::Future: 'static, S::Response: Into>, B: MessageBody + 'static, X: Service, X::Error: Into, U: Service), Response = ()>, U::Error: fmt::Display, { state: State, } const HTTP2_PREFACE: [u8; 14] = *b"PRI * HTTP/2.0"; impl Future for HttpServiceHandlerResponse where T: AsyncRead + AsyncWrite, S: Service, S::Error: Into, S::Future: 'static, S::Response: Into>, B: MessageBody, X: Service, X::Error: Into, U: Service), Response = ()>, U::Error: fmt::Display, { type Item = (); type Error = DispatchError; fn poll(&mut self) -> Poll { match self.state { State::H1(ref mut disp) => disp.poll(), State::H2(ref mut disp) => disp.poll(), State::Unknown(ref mut data) => { if let Some(ref mut item) = data { loop { unsafe { let b = item.1.bytes_mut(); let n = try_ready!(item.0.poll_read(b)); if n == 0 { return Ok(Async::Ready(())); } item.1.advance_mut(n); if item.1.len() >= HTTP2_PREFACE.len() { break; } } } } else { panic!() } let (io, buf, cfg, srv, expect, upgrade) = data.take().unwrap(); if buf[..14] == HTTP2_PREFACE[..] { let io = Io { inner: io, unread: Some(buf), }; self.state = State::Handshake(Some((server::handshake(io), cfg, srv))); } else { self.state = State::H1(h1::Dispatcher::with_timeout( io, h1::Codec::new(cfg.clone()), cfg, buf, None, srv, expect, upgrade, )) } self.poll() } State::Handshake(ref mut data) => { let conn = if let Some(ref mut item) = data { match item.0.poll() { Ok(Async::Ready(conn)) => conn, Ok(Async::NotReady) => return Ok(Async::NotReady), Err(err) => { trace!("H2 handshake error: {}", err); return Err(err.into()); } } } else { panic!() }; let (_, cfg, srv) = data.take().unwrap(); self.state = State::H2(Dispatcher::new(srv, conn, cfg, None)); self.poll() } } } } /// Wrapper for `AsyncRead + AsyncWrite` types struct Io { unread: Option, inner: T, } impl io::Read for Io { fn read(&mut self, buf: &mut [u8]) -> io::Result { if let Some(mut bytes) = self.unread.take() { let size = std::cmp::min(buf.len(), bytes.len()); buf[..size].copy_from_slice(&bytes[..size]); if bytes.len() > size { bytes.split_to(size); self.unread = Some(bytes); } Ok(size) } else { self.inner.read(buf) } } } impl io::Write for Io { fn write(&mut self, buf: &[u8]) -> io::Result { self.inner.write(buf) } fn flush(&mut self) -> io::Result<()> { self.inner.flush() } } impl AsyncRead for Io { unsafe fn prepare_uninitialized_buffer(&self, buf: &mut [u8]) -> bool { self.inner.prepare_uninitialized_buffer(buf) } } impl AsyncWrite for Io { fn shutdown(&mut self) -> Poll<(), io::Error> { self.inner.shutdown() } fn write_buf(&mut self, buf: &mut B) -> Poll { self.inner.write_buf(buf) } }