use std::marker::PhantomData; use std::rc::Rc; use std::{fmt, net}; use actix_codec::Framed; use actix_service::{IntoServiceFactory, Service, ServiceFactory}; use crate::body::MessageBody; use crate::config::{KeepAlive, ServiceConfig}; use crate::error::Error; use crate::h1::{Codec, ExpectHandler, H1Service, UpgradeHandler}; use crate::h2::H2Service; use crate::request::Request; use crate::response::Response; use crate::service::HttpService; use crate::{ConnectCallback, Extensions}; /// A HTTP service builder /// /// This type can be used to construct an instance of [`HttpService`] through a /// builder-like pattern. pub struct HttpServiceBuilder { keep_alive: KeepAlive, client_timeout: u64, client_disconnect: u64, secure: bool, local_addr: Option, expect: X, upgrade: Option, on_connect_ext: Option>>, _phantom: PhantomData, } impl HttpServiceBuilder where S: ServiceFactory, S::Error: Into + 'static, S::InitError: fmt::Debug, >::Future: 'static, { /// Create instance of `ServiceConfigBuilder` pub fn new() -> Self { HttpServiceBuilder { keep_alive: KeepAlive::Timeout(5), client_timeout: 5000, client_disconnect: 0, secure: false, local_addr: None, expect: ExpectHandler, upgrade: None, on_connect_ext: None, _phantom: PhantomData, } } } impl HttpServiceBuilder where S: ServiceFactory, S::Error: Into + 'static, S::InitError: fmt::Debug, >::Future: 'static, X: ServiceFactory, X::Error: Into, X::InitError: fmt::Debug, >::Future: 'static, U: ServiceFactory<(Request, Framed), Config = (), Response = ()>, U::Error: fmt::Display, U::InitError: fmt::Debug, )>>::Future: 'static, { /// Set server keep-alive setting. /// /// By default keep alive is set to a 5 seconds. pub fn keep_alive>(mut self, val: W) -> Self { self.keep_alive = val.into(); self } /// Set connection secure state pub fn secure(mut self) -> Self { self.secure = true; self } /// Set the local address that this service is bound to. pub fn local_addr(mut self, addr: net::SocketAddr) -> Self { self.local_addr = Some(addr); self } /// Set server client timeout in milliseconds for first request. /// /// Defines a timeout for reading client request header. If a client does not transmit /// the entire set headers within this time, the request is terminated with /// the 408 (Request Time-out) error. /// /// To disable timeout set value to 0. /// /// By default client timeout is set to 5000 milliseconds. pub fn client_timeout(mut self, val: u64) -> Self { self.client_timeout = val; self } /// Set server connection disconnect timeout in milliseconds. /// /// Defines a timeout for disconnect connection. If a disconnect procedure does not complete /// within this time, the request get dropped. This timeout affects secure connections. /// /// To disable timeout set value to 0. /// /// By default disconnect timeout is set to 0. pub fn client_disconnect(mut self, val: u64) -> Self { self.client_disconnect = val; self } /// 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: F) -> HttpServiceBuilder where F: IntoServiceFactory, X1: ServiceFactory, X1::Error: Into, X1::InitError: fmt::Debug, >::Future: 'static, { HttpServiceBuilder { keep_alive: self.keep_alive, client_timeout: self.client_timeout, client_disconnect: self.client_disconnect, secure: self.secure, local_addr: self.local_addr, expect: expect.into_factory(), upgrade: self.upgrade, on_connect_ext: self.on_connect_ext, _phantom: 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: F) -> HttpServiceBuilder where F: IntoServiceFactory)>, U1: ServiceFactory<(Request, Framed), Config = (), Response = ()>, U1::Error: fmt::Display, U1::InitError: fmt::Debug, )>>::Future: 'static, { HttpServiceBuilder { keep_alive: self.keep_alive, client_timeout: self.client_timeout, client_disconnect: self.client_disconnect, secure: self.secure, local_addr: self.local_addr, expect: self.expect, upgrade: Some(upgrade.into_factory()), on_connect_ext: self.on_connect_ext, _phantom: PhantomData, } } /// Sets the callback to be run on connection establishment. /// /// Has mutable access to a data container that will be merged into request extensions. /// This enables transport layer data (like client certificates) to be accessed in middleware /// and handlers. pub fn on_connect_ext(mut self, f: F) -> Self where F: Fn(&T, &mut Extensions) + 'static, { self.on_connect_ext = Some(Rc::new(f)); self } /// Finish service configuration and create a HTTP Service for HTTP/1 protocol. pub fn h1(self, service: F) -> H1Service where B: MessageBody, F: IntoServiceFactory, S::Error: Into, S::InitError: fmt::Debug, S::Response: Into>, { let cfg = ServiceConfig::new( self.keep_alive, self.client_timeout, self.client_disconnect, self.secure, self.local_addr, ); H1Service::with_config(cfg, service.into_factory()) .expect(self.expect) .upgrade(self.upgrade) .on_connect_ext(self.on_connect_ext) } /// Finish service configuration and create a HTTP service for HTTP/2 protocol. pub fn h2(self, service: F) -> H2Service where B: MessageBody + 'static, F: IntoServiceFactory, S::Error: Into + 'static, S::InitError: fmt::Debug, S::Response: Into> + 'static, >::Future: 'static, { let cfg = ServiceConfig::new( self.keep_alive, self.client_timeout, self.client_disconnect, self.secure, self.local_addr, ); H2Service::with_config(cfg, service.into_factory()) .on_connect_ext(self.on_connect_ext) } /// Finish service configuration and create `HttpService` instance. pub fn finish(self, service: F) -> HttpService where B: MessageBody + 'static, F: IntoServiceFactory, S::Error: Into + 'static, S::InitError: fmt::Debug, S::Response: Into> + 'static, >::Future: 'static, { let cfg = ServiceConfig::new( self.keep_alive, self.client_timeout, self.client_disconnect, self.secure, self.local_addr, ); HttpService::with_config(cfg, service.into_factory()) .expect(self.expect) .upgrade(self.upgrade) .on_connect_ext(self.on_connect_ext) } }