diff --git a/Cargo.toml b/Cargo.toml index 88a87427..973b2f2f 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -20,6 +20,7 @@ members = [ "actix-rt", "actix-service", "actix-server", + "actix-server-config", "actix-test-server", "actix-utils", "router", diff --git a/actix-connector/src/connector.rs b/actix-connector/src/connector.rs index ba18b474..e3c12cc2 100644 --- a/actix-connector/src/connector.rs +++ b/actix-connector/src/connector.rs @@ -167,8 +167,8 @@ impl Connector { /// Create new connector with custom resolver pub fn with_resolver( resolver: Resolver, - ) -> impl Service + Clone - { + ) -> impl Service + + Clone { Connector { resolver } } @@ -177,8 +177,8 @@ impl Connector { cfg: ResolverConfig, opts: ResolverOpts, ) -> impl NewService< - Connect, (), + Request = Connect, Response = (Connect, TcpStream), Error = ConnectorError, InitError = E, @@ -195,7 +195,8 @@ impl Clone for Connector { } } -impl Service for Connector { +impl Service for Connector { + type Request = Connect; type Response = (Connect, TcpStream); type Error = ConnectorError; type Future = Either; @@ -272,7 +273,8 @@ impl Default for TcpConnector { } } -impl Service<(T, VecDeque)> for TcpConnector { +impl Service for TcpConnector { + type Request = (T, VecDeque); type Response = (T, TcpStream); type Error = io::Error; type Future = TcpConnectorResponse; @@ -352,7 +354,8 @@ impl DefaultConnector { } } -impl Service for DefaultConnector { +impl Service for DefaultConnector { + type Request = Connect; type Response = TcpStream; type Error = ConnectorError; type Future = DefaultConnectorFuture; diff --git a/actix-connector/src/resolver.rs b/actix-connector/src/resolver.rs index d6ee2612..443fdd75 100644 --- a/actix-connector/src/resolver.rs +++ b/actix-connector/src/resolver.rs @@ -67,7 +67,8 @@ impl Clone for Resolver { } } -impl Service for Resolver { +impl Service for Resolver { + type Request = T; type Response = (T, VecDeque); type Error = ResolveError; type Future = ResolverFuture; diff --git a/actix-connector/src/ssl/openssl.rs b/actix-connector/src/ssl/openssl.rs index f05b17e5..3df9cab5 100644 --- a/actix-connector/src/ssl/openssl.rs +++ b/actix-connector/src/ssl/openssl.rs @@ -26,7 +26,8 @@ impl OpensslConnector { impl OpensslConnector { pub fn service( connector: SslConnector, - ) -> impl Service<(R, T), Response = (R, SslStream), Error = HandshakeError> { + ) -> impl Service), Error = HandshakeError> + { OpensslConnectorService { connector: connector, _t: PhantomData, @@ -43,9 +44,10 @@ impl Clone for OpensslConnector { } } -impl NewService<(R, T), ()> +impl NewService<()> for OpensslConnector { + type Request = (R, T); type Response = (R, SslStream); type Error = HandshakeError; type Service = OpensslConnectorService; @@ -65,9 +67,8 @@ pub struct OpensslConnectorService { _t: PhantomData<(R, T)>, } -impl Service<(R, T)> - for OpensslConnectorService -{ +impl Service for OpensslConnectorService { + type Request = (R, T); type Response = (R, SslStream); type Error = HandshakeError; type Future = ConnectAsyncExt; diff --git a/actix-server-config/Cargo.toml b/actix-server-config/Cargo.toml new file mode 100644 index 00000000..ab2de92b --- /dev/null +++ b/actix-server-config/Cargo.toml @@ -0,0 +1,18 @@ +[package] +name = "actix-server-config" +version = "0.1.0" +authors = ["Nikolay Kim "] +description = "Actix server config utils" +homepage = "https://actix.rs" +repository = "https://github.com/actix/actix-net.git" +license = "MIT/Apache-2.0" +edition = "2018" +workspace = ".." + +[lib] +name = "actix_server_config" +path = "src/lib.rs" + +[dependencies] +actix-service = { path="../actix-service" } +futures = "0.1.25" diff --git a/actix-server-config/src/lib.rs b/actix-server-config/src/lib.rs new file mode 100644 index 00000000..51accad1 --- /dev/null +++ b/actix-server-config/src/lib.rs @@ -0,0 +1,33 @@ +use std::cell::Cell; +use std::net::SocketAddr; +use std::rc::Rc; + +#[derive(Debug, Clone)] +pub struct ServerConfig { + addr: SocketAddr, + secure: Rc>, +} + +impl ServerConfig { + pub fn new(addr: SocketAddr) -> Self { + ServerConfig { + addr, + secure: Rc::new(Cell::new(false)), + } + } + + /// Returns the address of the local half of this TCP server socket + pub fn local_addr(&self) -> SocketAddr { + self.addr + } + + /// Returns true if connection is secure (tls enabled) + pub fn secure(&self) -> bool { + self.secure.as_ref().get() + } + + /// Set secure flag + pub fn set_secure(&self) { + self.secure.as_ref().set(true) + } +} diff --git a/actix-server/Cargo.toml b/actix-server/Cargo.toml index ee7e1143..3da83ba6 100644 --- a/actix-server/Cargo.toml +++ b/actix-server/Cargo.toml @@ -36,6 +36,7 @@ rust-tls = ["rustls", "tokio-rustls", "webpki", "webpki-roots"] actix-rt = "0.2.0" #actix-service = "0.3.2" actix-service = { path="../actix-service" } +actix-server-config = { path="../actix-server-config" } log = "0.4" num_cpus = "1.0" diff --git a/actix-server/src/builder.rs b/actix-server/src/builder.rs index f3d72dc6..86433c00 100644 --- a/actix-server/src/builder.rs +++ b/actix-server/src/builder.rs @@ -150,14 +150,15 @@ impl ServerBuilder { U: net::ToSocketAddrs, { let sockets = bind_addr(addr)?; - let token = self.token.next(); - self.services.push(StreamNewService::create( - name.as_ref().to_string(), - token, - factory.clone(), - )); for lst in sockets { + let token = self.token.next(); + self.services.push(StreamNewService::create( + name.as_ref().to_string(), + token, + factory.clone(), + lst.local_addr()?, + )); self.sockets.push((token, lst)); } Ok(self) @@ -178,6 +179,7 @@ impl ServerBuilder { name.as_ref().to_string(), token, factory, + lst.local_addr()?, )); self.sockets.push((token, lst)); Ok(self) diff --git a/actix-server/src/lib.rs b/actix-server/src/lib.rs index eecc46aa..a5ec2a72 100644 --- a/actix-server/src/lib.rs +++ b/actix-server/src/lib.rs @@ -10,6 +10,8 @@ mod signals; pub mod ssl; mod worker; +pub use actix_server_config::ServerConfig; + pub use self::builder::ServerBuilder; pub use self::server::Server; pub use self::service_config::{ServiceConfig, ServiceRuntime}; diff --git a/actix-server/src/service_config.rs b/actix-server/src/service_config.rs index c2fd5ec7..885f4254 100644 --- a/actix-server/src/service_config.rs +++ b/actix-server/src/service_config.rs @@ -169,8 +169,8 @@ impl ServiceRuntime { pub fn service(&mut self, name: &str, service: F) where - F: IntoNewService, - T: NewService + 'static, + F: IntoNewService, + T: NewService + 'static, T::Future: 'static, T::Service: 'static, T::InitError: fmt::Debug, @@ -191,7 +191,7 @@ impl ServiceRuntime { type BoxedNewService = Box< NewService< - (Option, ServerMessage), + Request = (Option, ServerMessage), Response = (), Error = (), InitError = (), @@ -204,14 +204,15 @@ struct ServiceFactory { inner: T, } -impl NewService<(Option, ServerMessage)> for ServiceFactory +impl NewService for ServiceFactory where - T: NewService, + T: NewService, T::Future: 'static, T::Service: 'static, T::Error: 'static, T::InitError: fmt::Debug + 'static, { + type Request = (Option, ServerMessage); type Response = (); type Error = (); type InitError = (); diff --git a/actix-server/src/services.rs b/actix-server/src/services.rs index a1df1c7b..9ef42d40 100644 --- a/actix-server/src/services.rs +++ b/actix-server/src/services.rs @@ -1,7 +1,8 @@ -use std::net::TcpStream; +use std::net::{SocketAddr, TcpStream}; use std::time::Duration; use actix_rt::spawn; +use actix_server_config::ServerConfig; use actix_service::{NewService, Service}; use futures::future::{err, ok, FutureResult}; use futures::{Future, Poll}; @@ -23,7 +24,7 @@ pub(crate) enum ServerMessage { } pub trait ServiceFactory: Send + Clone + 'static { - type NewService: NewService; + type NewService: NewService; fn create(&self) -> Self::NewService; } @@ -38,7 +39,7 @@ pub(crate) trait InternalServiceFactory: Send { pub(crate) type BoxedServerService = Box< Service< - (Option, ServerMessage), + Request = (Option, ServerMessage), Response = (), Error = (), Future = FutureResult<(), ()>, @@ -55,12 +56,13 @@ impl StreamService { } } -impl Service<(Option, ServerMessage)> for StreamService +impl Service for StreamService where - T: Service, + T: Service, T::Future: 'static, T::Error: 'static, { + type Request = (Option, ServerMessage); type Response = (); type Error = (); type Future = FutureResult<(), ()>; @@ -96,14 +98,25 @@ pub(crate) struct StreamNewService { name: String, inner: F, token: Token, + addr: SocketAddr, } impl StreamNewService where F: ServiceFactory, { - pub(crate) fn create(name: String, token: Token, inner: F) -> Box { - Box::new(Self { name, token, inner }) + pub(crate) fn create( + name: String, + token: Token, + inner: F, + addr: SocketAddr, + ) -> Box { + Box::new(Self { + name, + token, + inner, + addr, + }) } } @@ -120,15 +133,17 @@ where name: self.name.clone(), inner: self.inner.clone(), token: self.token, + addr: self.addr, }) } fn create(&self) -> Box, Error = ()>> { let token = self.token; + let config = ServerConfig::new(self.addr); Box::new( self.inner .create() - .new_service(&()) + .new_service(&config) .map_err(|_| ()) .map(move |inner| { let service: BoxedServerService = Box::new(StreamService::new(inner)); @@ -155,7 +170,7 @@ impl InternalServiceFactory for Box { impl ServiceFactory for F where F: Fn() -> T + Send + Clone + 'static, - T: NewService, + T: NewService, { type NewService = T; diff --git a/actix-server/src/ssl/nativetls.rs b/actix-server/src/ssl/nativetls.rs index f7108190..6b177586 100644 --- a/actix-server/src/ssl/nativetls.rs +++ b/actix-server/src/ssl/nativetls.rs @@ -1,6 +1,7 @@ use std::io; use std::marker::PhantomData; +use actix_server_config::ServerConfig; use actix_service::{NewService, Service}; use futures::{future::ok, future::FutureResult, Async, Future, Poll}; use native_tls::{self, Error, HandshakeError, TlsAcceptor}; @@ -36,14 +37,17 @@ impl Clone for NativeTlsAcceptor { } } -impl NewService for NativeTlsAcceptor { +impl NewService for NativeTlsAcceptor { + type Request = T; type Response = TlsStream; type Error = Error; type Service = NativeTlsAcceptorService; type InitError = (); type Future = FutureResult; - fn new_service(&self, _: &()) -> Self::Future { + fn new_service(&self, cfg: &ServerConfig) -> Self::Future { + cfg.set_secure(); + MAX_CONN_COUNTER.with(|conns| { ok(NativeTlsAcceptorService { acceptor: self.acceptor.clone(), @@ -60,7 +64,8 @@ pub struct NativeTlsAcceptorService { conns: Counter, } -impl Service for NativeTlsAcceptorService { +impl Service for NativeTlsAcceptorService { + type Request = T; type Response = TlsStream; type Error = Error; type Future = Accept; diff --git a/actix-server/src/ssl/openssl.rs b/actix-server/src/ssl/openssl.rs index 3c71e17e..5c464dd7 100644 --- a/actix-server/src/ssl/openssl.rs +++ b/actix-server/src/ssl/openssl.rs @@ -8,6 +8,7 @@ use tokio_openssl::{AcceptAsync, SslAcceptorExt, SslStream}; use crate::counter::{Counter, CounterGuard}; use crate::ssl::MAX_CONN_COUNTER; +use crate::ServerConfig; /// Support `SSL` connections via openssl package /// @@ -36,14 +37,17 @@ impl Clone for OpensslAcceptor { } } -impl NewService for OpensslAcceptor { +impl NewService for OpensslAcceptor { + type Request = T; type Response = SslStream; type Error = HandshakeError; type Service = OpensslAcceptorService; type InitError = (); type Future = FutureResult; - fn new_service(&self, _: &()) -> Self::Future { + fn new_service(&self, cfg: &ServerConfig) -> Self::Future { + cfg.set_secure(); + MAX_CONN_COUNTER.with(|conns| { ok(OpensslAcceptorService { acceptor: self.acceptor.clone(), @@ -60,7 +64,8 @@ pub struct OpensslAcceptorService { conns: Counter, } -impl Service for OpensslAcceptorService { +impl Service for OpensslAcceptorService { + type Request = T; type Response = SslStream; type Error = HandshakeError; type Future = OpensslAcceptorServiceFut; diff --git a/actix-server/src/ssl/rustls.rs b/actix-server/src/ssl/rustls.rs index 2aec4e1f..f824540b 100644 --- a/actix-server/src/ssl/rustls.rs +++ b/actix-server/src/ssl/rustls.rs @@ -10,6 +10,7 @@ use tokio_rustls::{Accept, TlsAcceptor, TlsStream}; use crate::counter::{Counter, CounterGuard}; use crate::ssl::MAX_CONN_COUNTER; +use crate::ServerConfig as SrvConfig; /// Support `SSL` connections via rustls package /// @@ -38,14 +39,17 @@ impl Clone for RustlsAcceptor { } } -impl NewService for RustlsAcceptor { +impl NewService for RustlsAcceptor { + type Request = T; type Response = TlsStream; type Error = io::Error; type Service = RustlsAcceptorService; type InitError = (); type Future = FutureResult; - fn new_service(&self, _: &()) -> Self::Future { + fn new_service(&self, cfg: &SrvConfig) -> Self::Future { + cfg.set_secure(); + MAX_CONN_COUNTER.with(|conns| { ok(RustlsAcceptorService { acceptor: self.config.clone().into(), @@ -62,7 +66,8 @@ pub struct RustlsAcceptorService { conns: Counter, } -impl Service for RustlsAcceptorService { +impl Service for RustlsAcceptorService { + type Request = T; type Response = TlsStream; type Error = io::Error; type Future = RustlsAcceptorServiceFut; diff --git a/actix-server/tests/test_server.rs b/actix-server/tests/test_server.rs index 934e33d7..ad4d3699 100644 --- a/actix-server/tests/test_server.rs +++ b/actix-server/tests/test_server.rs @@ -1,7 +1,7 @@ use std::{net, thread, time}; -use actix_server::Server; -use actix_service::fn_service; +use actix_server::{Server, ServerConfig}; +use actix_service::{fn_cfg_factory, fn_service, IntoService}; use net2::TcpBuilder; fn unused_addr() -> net::SocketAddr { @@ -19,7 +19,27 @@ fn test_bind() { thread::spawn(move || { Server::build() - .bind("test", addr, || fn_service(|_| Ok::<_, ()>(()))) + .bind("test", addr, move || { + fn_cfg_factory(move |cfg: &ServerConfig| { + assert_eq!(cfg.local_addr(), addr); + Ok::<_, ()>((|_| Ok::<_, ()>(())).into_service()) + }) + }) + .unwrap() + .run() + }); + + thread::sleep(time::Duration::from_millis(500)); + assert!(net::TcpStream::connect(addr).is_ok()); +} + +#[test] +fn test_bind_no_config() { + let addr = unused_addr(); + + thread::spawn(move || { + Server::build() + .bind("test", addr, move || fn_service(|_| Ok::<_, ()>(()))) .unwrap() .run() }); @@ -35,7 +55,12 @@ fn test_listen() { thread::spawn(move || { let lst = net::TcpListener::bind(addr).unwrap(); Server::build() - .listen("test", lst, move || fn_service(|_| Ok::<_, ()>(()))) + .listen("test", lst, move || { + fn_cfg_factory(move |cfg: &ServerConfig| { + assert_eq!(cfg.local_addr(), addr); + Ok::<_, ()>((|_| Ok::<_, ()>(())).into_service()) + }) + }) .unwrap() .run() });