From d026821924cc97482c334952e214f0f86b1ee0e0 Mon Sep 17 00:00:00 2001 From: Nikolay Kim Date: Sat, 9 Mar 2019 10:39:06 -0800 Subject: [PATCH] unify service builders --- examples/echo.rs | 7 +- examples/echo2.rs | 10 +- examples/hello-world.rs | 7 +- src/builder.rs | 141 ++++++++++++++++++++++++++++ src/config.rs | 118 +----------------------- src/h1/service.rs | 136 --------------------------- src/h2/service.rs | 135 --------------------------- src/lib.rs | 4 +- src/service/service.rs | 155 +------------------------------ tests/test_client.rs | 8 +- tests/test_server.rs | 198 ++++++++++++++++++++++++++++------------ 11 files changed, 300 insertions(+), 619 deletions(-) create mode 100644 src/builder.rs diff --git a/examples/echo.rs b/examples/echo.rs index eb4aaa657..8ec0e6a97 100644 --- a/examples/echo.rs +++ b/examples/echo.rs @@ -1,9 +1,8 @@ use std::{env, io}; use actix_http::HttpMessage; -use actix_http::{h1, Request, Response}; +use actix_http::{HttpService, Request, Response}; use actix_server::Server; -use actix_service::NewService; use bytes::Bytes; use futures::Future; use http::header::HeaderValue; @@ -15,10 +14,9 @@ fn main() -> io::Result<()> { Server::build() .bind("echo", "127.0.0.1:8080", || { - h1::H1Service::build() + HttpService::build() .client_timeout(1000) .client_disconnect(1000) - .server_hostname("localhost") .finish(|mut req: Request| { req.body().limit(512).and_then(|bytes: Bytes| { info!("request body: {:?}", bytes); @@ -27,7 +25,6 @@ fn main() -> io::Result<()> { Ok(res.body(bytes)) }) }) - .map(|_| ()) })? .run() } diff --git a/examples/echo2.rs b/examples/echo2.rs index 3bb8d83d5..101adc1cf 100644 --- a/examples/echo2.rs +++ b/examples/echo2.rs @@ -2,9 +2,8 @@ use std::{env, io}; use actix_http::http::HeaderValue; use actix_http::HttpMessage; -use actix_http::{h1, Error, Request, Response}; +use actix_http::{Error, HttpService, Request, Response}; use actix_server::Server; -use actix_service::NewService; use bytes::Bytes; use futures::Future; use log::info; @@ -24,12 +23,7 @@ fn main() -> io::Result<()> { Server::build() .bind("echo", "127.0.0.1:8080", || { - h1::H1Service::build() - .client_timeout(1000) - .client_disconnect(1000) - .server_hostname("localhost") - .finish(|_req: Request| handle_request(_req)) - .map(|_| ()) + HttpService::build().finish(|_req: Request| handle_request(_req)) })? .run() } diff --git a/examples/hello-world.rs b/examples/hello-world.rs index 05d69fed8..6e3820390 100644 --- a/examples/hello-world.rs +++ b/examples/hello-world.rs @@ -1,8 +1,7 @@ use std::{env, io}; -use actix_http::{h1, Response}; +use actix_http::{HttpService, Response}; use actix_server::Server; -use actix_service::NewService; use futures::future; use http::header::HeaderValue; use log::info; @@ -13,17 +12,15 @@ fn main() -> io::Result<()> { Server::build() .bind("hello-world", "127.0.0.1:8080", || { - h1::H1Service::build() + HttpService::build() .client_timeout(1000) .client_disconnect(1000) - .server_hostname("localhost") .finish(|_req| { info!("{:?}", _req); let mut res = Response::Ok(); res.header("x-head", HeaderValue::from_static("dummy value!")); future::ok::<_, ()>(res.body("Hello world!")) }) - .map(|_| ()) })? .run() } diff --git a/src/builder.rs b/src/builder.rs new file mode 100644 index 000000000..c55b8d5fc --- /dev/null +++ b/src/builder.rs @@ -0,0 +1,141 @@ +use std::fmt::Debug; +use std::marker::PhantomData; + +use actix_server_config::ServerConfig as SrvConfig; +use actix_service::{IntoNewService, NewService}; + +use crate::body::MessageBody; +use crate::config::{KeepAlive, ServiceConfig}; +use crate::request::Request; +use crate::response::Response; + +use crate::h1::H1Service; +use crate::h2::H2Service; +use crate::service::HttpService; + +/// A http service builder +/// +/// This type can be used to construct an instance of `http service` through a +/// builder-like pattern. +pub struct HttpServiceBuilder { + keep_alive: KeepAlive, + client_timeout: u64, + client_disconnect: u64, + _t: PhantomData<(T, S)>, +} + +impl HttpServiceBuilder +where + S: NewService, + S::Error: Debug + 'static, + S::Service: 'static, +{ + /// Create instance of `ServiceConfigBuilder` + pub fn new() -> HttpServiceBuilder { + HttpServiceBuilder { + keep_alive: KeepAlive::Timeout(5), + client_timeout: 5000, + client_disconnect: 0, + _t: PhantomData, + } + } + + /// Set server keep-alive setting. + /// + /// By default keep alive is set to a 5 seconds. + pub fn keep_alive>(mut self, val: U) -> Self { + self.keep_alive = val.into(); + 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 3000 milliseconds. + pub fn client_disconnect(mut self, val: u64) -> Self { + self.client_disconnect = val; + self + } + + // #[cfg(feature = "ssl")] + // /// Configure alpn protocols for SslAcceptorBuilder. + // pub fn configure_openssl( + // builder: &mut openssl::ssl::SslAcceptorBuilder, + // ) -> io::Result<()> { + // let protos: &[u8] = b"\x02h2"; + // builder.set_alpn_select_callback(|_, protos| { + // const H2: &[u8] = b"\x02h2"; + // if protos.windows(3).any(|window| window == H2) { + // Ok(b"h2") + // } else { + // Err(openssl::ssl::AlpnError::NOACK) + // } + // }); + // builder.set_alpn_protos(&protos)?; + + // Ok(()) + // } + + /// Finish service configuration and create *http service* for HTTP/1 protocol. + pub fn h1(self, service: F) -> H1Service + where + B: MessageBody + 'static, + F: IntoNewService, + S::Response: Into>, + { + let cfg = ServiceConfig::new( + self.keep_alive, + self.client_timeout, + self.client_disconnect, + ); + H1Service::with_config(cfg, service.into_new_service()) + } + + /// Finish service configuration and create *http service* for HTTP/2 protocol. + pub fn h2(self, service: F) -> H2Service + where + B: MessageBody + 'static, + F: IntoNewService, + S::Response: Into>, + { + let cfg = ServiceConfig::new( + self.keep_alive, + self.client_timeout, + self.client_disconnect, + ); + H2Service::with_config(cfg, service.into_new_service()) + } + + /// Finish service configuration and create `HttpService` instance. + pub fn finish(self, service: F) -> HttpService + where + B: MessageBody + 'static, + F: IntoNewService, + S::Response: Into>, + { + let cfg = ServiceConfig::new( + self.keep_alive, + self.client_timeout, + self.client_disconnect, + ); + HttpService::with_config(cfg, service.into_new_service()) + } +} diff --git a/src/config.rs b/src/config.rs index a9e705c95..3c7df2feb 100644 --- a/src/config.rs +++ b/src/config.rs @@ -1,12 +1,11 @@ use std::cell::UnsafeCell; +use std::fmt; use std::fmt::Write; use std::rc::Rc; use std::time::{Duration, Instant}; -use std::{fmt, net}; use bytes::BytesMut; use futures::{future, Future}; -use log::error; use time; use tokio_timer::{sleep, Delay}; @@ -90,11 +89,6 @@ impl ServiceConfig { })) } - /// Create worker settings builder. - pub fn build() -> ServiceConfigBuilder { - ServiceConfigBuilder::new() - } - #[inline] /// Keep alive duration if configured. pub fn keep_alive(&self) -> Option { @@ -177,116 +171,6 @@ impl ServiceConfig { } } -/// A service config builder -/// -/// This type can be used to construct an instance of `ServiceConfig` through a -/// builder-like pattern. -pub struct ServiceConfigBuilder { - keep_alive: KeepAlive, - client_timeout: u64, - client_disconnect: u64, - host: String, - addr: net::SocketAddr, - secure: bool, -} - -impl ServiceConfigBuilder { - /// Create instance of `ServiceConfigBuilder` - pub fn new() -> ServiceConfigBuilder { - ServiceConfigBuilder { - keep_alive: KeepAlive::Timeout(5), - client_timeout: 5000, - client_disconnect: 0, - secure: false, - host: "localhost".to_owned(), - addr: "127.0.0.1:8080".parse().unwrap(), - } - } - - /// Enable secure flag for current server. - /// This flags also enables `client disconnect timeout`. - /// - /// By default this flag is set to false. - pub fn secure(mut self) -> Self { - self.secure = true; - if self.client_disconnect == 0 { - self.client_disconnect = 3000; - } - self - } - - /// Set server keep-alive setting. - /// - /// By default keep alive is set to a 5 seconds. - pub fn keep_alive>(mut self, val: T) -> Self { - self.keep_alive = val.into(); - 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 3000 milliseconds. - pub fn client_disconnect(mut self, val: u64) -> Self { - self.client_disconnect = val; - self - } - - /// Set server host name. - /// - /// Host name is used by application router aa a hostname for url - /// generation. Check [ConnectionInfo](./dev/struct.ConnectionInfo. - /// html#method.host) documentation for more information. - /// - /// By default host name is set to a "localhost" value. - pub fn server_hostname(mut self, val: &str) -> Self { - self.host = val.to_owned(); - self - } - - /// Set server ip address. - /// - /// Host name is used by application router aa a hostname for url - /// generation. Check [ConnectionInfo](./dev/struct.ConnectionInfo. - /// html#method.host) documentation for more information. - /// - /// By default server address is set to a "127.0.0.1:8080" - pub fn server_address(mut self, addr: S) -> Self { - match addr.to_socket_addrs() { - Err(err) => error!("Can not convert to SocketAddr: {}", err), - Ok(mut addrs) => { - if let Some(addr) = addrs.next() { - self.addr = addr; - } - } - } - self - } - - /// Finish service configuration and create `ServiceConfig` object. - pub fn finish(&mut self) -> ServiceConfig { - ServiceConfig::new(self.keep_alive, self.client_timeout, self.client_disconnect) - } -} - struct Date { bytes: [u8; DATE_VALUE_LENGTH], pos: usize, diff --git a/src/h1/service.rs b/src/h1/service.rs index 6a36678b3..e55ff0d99 100644 --- a/src/h1/service.rs +++ b/src/h1/service.rs @@ -1,6 +1,5 @@ use std::fmt::Debug; use std::marker::PhantomData; -use std::net; use actix_codec::{AsyncRead, AsyncWrite, Framed}; use actix_server_config::ServerConfig as SrvConfig; @@ -8,7 +7,6 @@ use actix_service::{IntoNewService, NewService, Service}; use actix_utils::cloneable::CloneableService; use futures::future::{ok, FutureResult}; use futures::{try_ready, Async, Future, IntoFuture, Poll, Stream}; -use log::error; use crate::body::MessageBody; use crate::config::{KeepAlive, ServiceConfig}; @@ -57,11 +55,6 @@ where _t: PhantomData, } } - - /// Create builder for `HttpService` instance. - pub fn build() -> H1ServiceBuilder { - H1ServiceBuilder::new() - } } impl NewService for H1Service @@ -89,135 +82,6 @@ where } } -/// A http/1 new service builder -/// -/// This type can be used to construct an instance of `ServiceConfig` through a -/// builder-like pattern. -pub struct H1ServiceBuilder { - keep_alive: KeepAlive, - client_timeout: u64, - client_disconnect: u64, - host: String, - addr: net::SocketAddr, - secure: bool, - _t: PhantomData<(T, S)>, -} - -impl H1ServiceBuilder -where - S: NewService, - S::Error: Debug, -{ - /// Create instance of `ServiceConfigBuilder` - pub fn new() -> H1ServiceBuilder { - H1ServiceBuilder { - keep_alive: KeepAlive::Timeout(5), - client_timeout: 5000, - client_disconnect: 0, - secure: false, - host: "localhost".to_owned(), - addr: "127.0.0.1:8080".parse().unwrap(), - _t: PhantomData, - } - } - - /// Enable secure flag for current server. - /// This flags also enables `client disconnect timeout`. - /// - /// By default this flag is set to false. - pub fn secure(mut self) -> Self { - self.secure = true; - if self.client_disconnect == 0 { - self.client_disconnect = 3000; - } - self - } - - /// Set server keep-alive setting. - /// - /// By default keep alive is set to a 5 seconds. - pub fn keep_alive>(mut self, val: U) -> Self { - self.keep_alive = val.into(); - 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 3000 milliseconds. - pub fn client_disconnect(mut self, val: u64) -> Self { - self.client_disconnect = val; - self - } - - /// Set server host name. - /// - /// Host name is used by application router aa a hostname for url - /// generation. Check [ConnectionInfo](./dev/struct.ConnectionInfo. - /// html#method.host) documentation for more information. - /// - /// By default host name is set to a "localhost" value. - pub fn server_hostname(mut self, val: &str) -> Self { - self.host = val.to_owned(); - self - } - - /// Set server ip address. - /// - /// Host name is used by application router aa a hostname for url - /// generation. Check [ConnectionInfo](./dev/struct.ConnectionInfo. - /// html#method.host) documentation for more information. - /// - /// By default server address is set to a "127.0.0.1:8080" - pub fn server_address(mut self, addr: U) -> Self { - match addr.to_socket_addrs() { - Err(err) => error!("Can not convert to SocketAddr: {}", err), - Ok(mut addrs) => { - if let Some(addr) = addrs.next() { - self.addr = addr; - } - } - } - self - } - - /// Finish service configuration and create `H1Service` instance. - pub fn finish(self, service: F) -> H1Service - where - B: MessageBody, - F: IntoNewService, - { - let cfg = ServiceConfig::new( - self.keep_alive, - self.client_timeout, - self.client_disconnect, - ); - H1Service { - cfg, - srv: service.into_new_service(), - _t: PhantomData, - } - } -} - #[doc(hidden)] pub struct H1ServiceResponse, B> { fut: ::Future, diff --git a/src/h2/service.rs b/src/h2/service.rs index 57515d4e8..ce7c3b5dd 100644 --- a/src/h2/service.rs +++ b/src/h2/service.rs @@ -59,11 +59,6 @@ where _t: PhantomData, } } - - /// Create builder for `HttpService` instance. - pub fn build() -> H2ServiceBuilder { - H2ServiceBuilder::new() - } } impl NewService for H2Service @@ -91,136 +86,6 @@ where } } -/// A http/2 new service builder -/// -/// This type can be used to construct an instance of `ServiceConfig` through a -/// builder-like pattern. -pub struct H2ServiceBuilder { - keep_alive: KeepAlive, - client_timeout: u64, - client_disconnect: u64, - host: String, - addr: net::SocketAddr, - secure: bool, - _t: PhantomData<(T, S)>, -} - -impl H2ServiceBuilder -where - S: NewService, - S::Service: 'static, - S::Error: Debug + 'static, -{ - /// Create instance of `H2ServiceBuilder` - pub fn new() -> H2ServiceBuilder { - H2ServiceBuilder { - keep_alive: KeepAlive::Timeout(5), - client_timeout: 5000, - client_disconnect: 0, - secure: false, - host: "localhost".to_owned(), - addr: "127.0.0.1:8080".parse().unwrap(), - _t: PhantomData, - } - } - - /// Enable secure flag for current server. - /// This flags also enables `client disconnect timeout`. - /// - /// By default this flag is set to false. - pub fn secure(mut self) -> Self { - self.secure = true; - if self.client_disconnect == 0 { - self.client_disconnect = 3000; - } - self - } - - /// Set server keep-alive setting. - /// - /// By default keep alive is set to a 5 seconds. - pub fn keep_alive>(mut self, val: U) -> Self { - self.keep_alive = val.into(); - 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 3000 milliseconds. - pub fn client_disconnect(mut self, val: u64) -> Self { - self.client_disconnect = val; - self - } - - /// Set server host name. - /// - /// Host name is used by application router aa a hostname for url - /// generation. Check [ConnectionInfo](./dev/struct.ConnectionInfo. - /// html#method.host) documentation for more information. - /// - /// By default host name is set to a "localhost" value. - pub fn server_hostname(mut self, val: &str) -> Self { - self.host = val.to_owned(); - self - } - - /// Set server ip address. - /// - /// Host name is used by application router aa a hostname for url - /// generation. Check [ConnectionInfo](./dev/struct.ConnectionInfo. - /// html#method.host) documentation for more information. - /// - /// By default server address is set to a "127.0.0.1:8080" - pub fn server_address(mut self, addr: U) -> Self { - match addr.to_socket_addrs() { - Err(err) => error!("Can not convert to SocketAddr: {}", err), - Ok(mut addrs) => { - if let Some(addr) = addrs.next() { - self.addr = addr; - } - } - } - self - } - - /// Finish service configuration and create `H1Service` instance. - pub fn finish(self, service: F) -> H2Service - where - B: MessageBody, - F: IntoNewService, - { - let cfg = ServiceConfig::new( - self.keep_alive, - self.client_timeout, - self.client_disconnect, - ); - H2Service { - cfg, - srv: service.into_new_service(), - _t: PhantomData, - } - } -} - #[doc(hidden)] pub struct H2ServiceResponse, B> { fut: ::Future, diff --git a/src/lib.rs b/src/lib.rs index 9d8bc50f1..41ee55fec 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -69,6 +69,7 @@ extern crate log; pub mod body; +mod builder; pub mod client; mod config; mod extensions; @@ -89,7 +90,8 @@ pub mod h2; pub mod test; pub mod ws; -pub use self::config::{KeepAlive, ServiceConfig, ServiceConfigBuilder}; +pub use self::builder::HttpServiceBuilder; +pub use self::config::{KeepAlive, ServiceConfig}; pub use self::error::{Error, ResponseError, Result}; pub use self::extensions::Extensions; pub use self::httpmessage::HttpMessage; diff --git a/src/service/service.rs b/src/service/service.rs index 0fa5d6653..ac28c77a5 100644 --- a/src/service/service.rs +++ b/src/service/service.rs @@ -1,6 +1,6 @@ use std::fmt::Debug; use std::marker::PhantomData; -use std::{fmt, io, net}; +use std::{fmt, io}; use actix_codec::{AsyncRead, AsyncWrite, Framed, FramedParts}; use actix_server_config::ServerConfig as SrvConfig; @@ -12,11 +12,11 @@ use h2::server::{self, Handshake}; use log::error; use crate::body::MessageBody; +use crate::builder::HttpServiceBuilder; use crate::config::{KeepAlive, ServiceConfig}; use crate::error::DispatchError; use crate::request::Request; use crate::response::Response; - use crate::{h1, h2::Dispatcher}; /// `NewService` HTTP1.1/HTTP2 transport implementation @@ -46,7 +46,7 @@ where } /// Create new `HttpService` instance with config. - pub fn with_config>( + pub(crate) fn with_config>( cfg: ServiceConfig, service: F, ) -> Self { @@ -88,155 +88,6 @@ where } } -/// A http service factory builder -/// -/// This type can be used to construct an instance of `ServiceConfig` through a -/// builder-like pattern. -pub struct HttpServiceBuilder { - keep_alive: KeepAlive, - client_timeout: u64, - client_disconnect: u64, - host: String, - addr: net::SocketAddr, - secure: bool, - _t: PhantomData<(T, S)>, -} - -impl HttpServiceBuilder -where - S: NewService, - S::Service: 'static, - S::Error: Debug + 'static, -{ - /// Create instance of `HttpServiceBuilder` type - pub fn new() -> HttpServiceBuilder { - HttpServiceBuilder { - keep_alive: KeepAlive::Timeout(5), - client_timeout: 5000, - client_disconnect: 0, - secure: false, - host: "localhost".to_owned(), - addr: "127.0.0.1:8080".parse().unwrap(), - _t: PhantomData, - } - } - - /// Enable secure flag for current server. - /// This flags also enables `client disconnect timeout`. - /// - /// By default this flag is set to false. - pub fn secure(mut self) -> Self { - self.secure = true; - if self.client_disconnect == 0 { - self.client_disconnect = 3000; - } - self - } - - /// Set server keep-alive setting. - /// - /// By default keep alive is set to a 5 seconds. - pub fn keep_alive>(mut self, val: U) -> Self { - self.keep_alive = val.into(); - 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 3000 milliseconds. - pub fn client_disconnect(mut self, val: u64) -> Self { - self.client_disconnect = val; - self - } - - /// Set server host name. - /// - /// Host name is used by application router aa a hostname for url - /// generation. Check [ConnectionInfo](./dev/struct.ConnectionInfo. - /// html#method.host) documentation for more information. - /// - /// By default host name is set to a "localhost" value. - pub fn server_hostname(mut self, val: &str) -> Self { - self.host = val.to_owned(); - self - } - - /// Set server ip address. - /// - /// Host name is used by application router aa a hostname for url - /// generation. Check [ConnectionInfo](./dev/struct.ConnectionInfo. - /// html#method.host) documentation for more information. - /// - /// By default server address is set to a "127.0.0.1:8080" - pub fn server_address(mut self, addr: U) -> Self { - match addr.to_socket_addrs() { - Err(err) => error!("Can not convert to SocketAddr: {}", err), - Ok(mut addrs) => { - if let Some(addr) = addrs.next() { - self.addr = addr; - } - } - } - self - } - - // #[cfg(feature = "ssl")] - // /// Configure alpn protocols for SslAcceptorBuilder. - // pub fn configure_openssl( - // builder: &mut openssl::ssl::SslAcceptorBuilder, - // ) -> io::Result<()> { - // let protos: &[u8] = b"\x02h2"; - // builder.set_alpn_select_callback(|_, protos| { - // const H2: &[u8] = b"\x02h2"; - // if protos.windows(3).any(|window| window == H2) { - // Ok(b"h2") - // } else { - // Err(openssl::ssl::AlpnError::NOACK) - // } - // }); - // builder.set_alpn_protos(&protos)?; - - // Ok(()) - // } - - /// Finish service configuration and create `HttpService` instance. - pub fn finish(self, service: F) -> HttpService - where - B: MessageBody, - F: IntoNewService, - { - let cfg = ServiceConfig::new( - self.keep_alive, - self.client_timeout, - self.client_disconnect, - ); - HttpService { - cfg, - srv: service.into_new_service(), - _t: PhantomData, - } - } -} - #[doc(hidden)] pub struct HttpServiceResponse, B> { fut: ::Future, diff --git a/tests/test_client.rs b/tests/test_client.rs index f44c45cbc..782e487ca 100644 --- a/tests/test_client.rs +++ b/tests/test_client.rs @@ -3,7 +3,7 @@ use bytes::Bytes; use futures::future::{self, ok}; use actix_http::HttpMessage; -use actix_http::{client, h1, Request, Response}; +use actix_http::{client, HttpService, Request, Response}; use actix_http_test::TestServer; const STR: &str = "Hello World Hello World Hello World Hello World Hello World \ @@ -32,7 +32,7 @@ const STR: &str = "Hello World Hello World Hello World Hello World Hello World \ fn test_h1_v2() { env_logger::init(); let mut srv = TestServer::new(move || { - h1::H1Service::build() + HttpService::build() .finish(|_| future::ok::<_, ()>(Response::Ok().body(STR))) .map(|_| ()) }); @@ -66,7 +66,7 @@ fn test_h1_v2() { #[test] fn test_connection_close() { let mut srv = TestServer::new(move || { - h1::H1Service::build() + HttpService::build() .finish(|_| ok::<_, ()>(Response::Ok().body(STR))) .map(|_| ()) }); @@ -80,7 +80,7 @@ fn test_connection_close() { #[test] fn test_with_query_parameter() { let mut srv = TestServer::new(move || { - h1::H1Service::build() + HttpService::build() .finish(|req: Request| { if req.uri().query().unwrap().contains("qp=") { ok::<_, ()>(Response::Ok().finish()) diff --git a/tests/test_server.rs b/tests/test_server.rs index b7cd5557b..7a28bca8a 100644 --- a/tests/test_server.rs +++ b/tests/test_server.rs @@ -10,20 +10,18 @@ use futures::stream::once; use actix_http::body::Body; use actix_http::{ - body, client, h1, h2, http, Error, HttpMessage as HttpMessage2, HttpService, - KeepAlive, Request, Response, + body, client, http, Error, HttpMessage as HttpMessage2, HttpService, KeepAlive, + Request, Response, }; #[test] fn test_h1() { let mut srv = TestServer::new(|| { - h1::H1Service::build() + HttpService::build() .keep_alive(KeepAlive::Disabled) .client_timeout(1000) .client_disconnect(1000) - .server_hostname("localhost") - .finish(|_| future::ok::<_, ()>(Response::Ok().finish())) - .map(|_| ()) + .h1(|_| future::ok::<_, ()>(Response::Ok().finish())) }); let req = client::ClientRequest::get(srv.url("/")).finish().unwrap(); @@ -38,7 +36,6 @@ fn test_h1_2() { .keep_alive(KeepAlive::Disabled) .client_timeout(1000) .client_disconnect(1000) - .server_hostname("localhost") .finish(|req: Request| { assert_eq!(req.version(), http::Version::HTTP_11); future::ok::<_, ()>(Response::Ok().finish()) @@ -83,8 +80,8 @@ fn test_h2() -> std::io::Result<()> { .clone() .map_err(|e| println!("Openssl error: {}", e)) .and_then( - h2::H2Service::build() - .finish(|_| future::ok::<_, Error>(Response::Ok().finish())) + HttpService::build() + .h2(|_| future::ok::<_, Error>(Response::Ok().finish())) .map_err(|_| ()), ) }); @@ -129,8 +126,8 @@ fn test_h2_body() -> std::io::Result<()> { .clone() .map_err(|e| println!("Openssl error: {}", e)) .and_then( - h2::H2Service::build() - .finish(|mut req: Request<_>| { + HttpService::build() + .h2(|mut req: Request<_>| { req.body() .limit(1024 * 1024) .and_then(|body| Ok(Response::Ok().body(body))) @@ -153,10 +150,9 @@ fn test_h2_body() -> std::io::Result<()> { #[test] fn test_slow_request() { let srv = TestServer::new(|| { - h1::H1Service::build() + HttpService::build() .client_timeout(100) - .finish(|_| future::ok::<_, ()>(Response::Ok().finish())) - .map(|_| ()) + .h1(|_| future::ok::<_, ()>(Response::Ok().finish())) }); let mut stream = net::TcpStream::connect(srv.addr()).unwrap(); @@ -167,9 +163,9 @@ fn test_slow_request() { } #[test] -fn test_malformed_request() { +fn test_http1_malformed_request() { let srv = TestServer::new(|| { - h1::H1Service::new(|_| future::ok::<_, ()>(Response::Ok().finish())).map(|_| ()) + HttpService::build().h1(|_| future::ok::<_, ()>(Response::Ok().finish())) }); let mut stream = net::TcpStream::connect(srv.addr()).unwrap(); @@ -180,11 +176,9 @@ fn test_malformed_request() { } #[test] -fn test_keepalive() { +fn test_http1_keepalive() { let srv = TestServer::new(|| { - h1::H1Service::build() - .finish(|_| future::ok::<_, ()>(Response::Ok().finish())) - .map(|_| ()) + HttpService::build().h1(|_| future::ok::<_, ()>(Response::Ok().finish())) }); let mut stream = net::TcpStream::connect(srv.addr()).unwrap(); @@ -200,12 +194,11 @@ fn test_keepalive() { } #[test] -fn test_keepalive_timeout() { +fn test_http1_keepalive_timeout() { let srv = TestServer::new(|| { - h1::H1Service::build() + HttpService::build() .keep_alive(1) - .finish(|_| future::ok::<_, ()>(Response::Ok().finish())) - .map(|_| ()) + .h1(|_| future::ok::<_, ()>(Response::Ok().finish())) }); let mut stream = net::TcpStream::connect(srv.addr()).unwrap(); @@ -221,11 +214,9 @@ fn test_keepalive_timeout() { } #[test] -fn test_keepalive_close() { +fn test_http1_keepalive_close() { let srv = TestServer::new(|| { - h1::H1Service::build() - .finish(|_| future::ok::<_, ()>(Response::Ok().finish())) - .map(|_| ()) + HttpService::build().h1(|_| future::ok::<_, ()>(Response::Ok().finish())) }); let mut stream = net::TcpStream::connect(srv.addr()).unwrap(); @@ -241,11 +232,9 @@ fn test_keepalive_close() { } #[test] -fn test_keepalive_http10_default_close() { +fn test_http10_keepalive_default_close() { let srv = TestServer::new(|| { - h1::H1Service::build() - .finish(|_| future::ok::<_, ()>(Response::Ok().finish())) - .map(|_| ()) + HttpService::build().h1(|_| future::ok::<_, ()>(Response::Ok().finish())) }); let mut stream = net::TcpStream::connect(srv.addr()).unwrap(); @@ -260,11 +249,9 @@ fn test_keepalive_http10_default_close() { } #[test] -fn test_keepalive_http10() { +fn test_http10_keepalive() { let srv = TestServer::new(|| { - h1::H1Service::build() - .finish(|_| future::ok::<_, ()>(Response::Ok().finish())) - .map(|_| ()) + HttpService::build().h1(|_| future::ok::<_, ()>(Response::Ok().finish())) }); let mut stream = net::TcpStream::connect(srv.addr()).unwrap(); @@ -286,12 +273,11 @@ fn test_keepalive_http10() { } #[test] -fn test_keepalive_disabled() { +fn test_http1_keepalive_disabled() { let srv = TestServer::new(|| { - h1::H1Service::build() + HttpService::build() .keep_alive(KeepAlive::Disabled) - .finish(|_| future::ok::<_, ()>(Response::Ok().finish())) - .map(|_| ()) + .h1(|_| future::ok::<_, ()>(Response::Ok().finish())) }); let mut stream = net::TcpStream::connect(srv.addr()).unwrap(); @@ -313,7 +299,7 @@ fn test_content_length() { }; let mut srv = TestServer::new(|| { - h1::H1Service::new(|req: Request| { + HttpService::build().h1(|req: Request| { let indx: usize = req.uri().path()[1..].parse().unwrap(); let statuses = [ StatusCode::NO_CONTENT, @@ -325,7 +311,6 @@ fn test_content_length() { ]; future::ok::<_, ()>(Response::new(statuses[indx])) }) - .map(|_| ()) }); let header = HeaderName::from_static("content-length"); @@ -356,6 +341,65 @@ fn test_content_length() { } } +// TODO: fix +// #[test] +// fn test_h2_content_length() { +// use actix_http::http::{ +// header::{HeaderName, HeaderValue}, +// StatusCode, +// }; +// let openssl = ssl_acceptor().unwrap(); + +// let mut srv = TestServer::new(move || { +// openssl +// .clone() +// .map_err(|e| println!("Openssl error: {}", e)) +// .and_then( +// HttpService::build() +// .h2(|req: Request| { +// let indx: usize = req.uri().path()[1..].parse().unwrap(); +// let statuses = [ +// StatusCode::NO_CONTENT, +// StatusCode::CONTINUE, +// StatusCode::SWITCHING_PROTOCOLS, +// StatusCode::PROCESSING, +// StatusCode::OK, +// StatusCode::NOT_FOUND, +// ]; +// future::ok::<_, ()>(Response::new(statuses[indx])) +// }) +// .map_err(|_| ()), +// ) +// }); + +// let header = HeaderName::from_static("content-length"); +// let value = HeaderValue::from_static("0"); + +// { +// for i in 0..4 { +// let req = client::ClientRequest::get(srv.surl(&format!("/{}", i))) +// .finish() +// .unwrap(); +// let response = srv.send_request(req).unwrap(); +// assert_eq!(response.headers().get(&header), None); + +// let req = client::ClientRequest::head(srv.surl(&format!("/{}", i))) +// .finish() +// .unwrap(); +// let response = srv.send_request(req).unwrap(); +// assert_eq!(response.headers().get(&header), None); +// } + +// for i in 4..6 { +// let req = client::ClientRequest::get(srv.surl(&format!("/{}", i))) +// .finish() +// .unwrap(); +// let response = srv.send_request(req).unwrap(); +// assert_eq!(response.headers().get(&header), Some(&value)); +// } +// } +// } + #[test] fn test_headers() { let data = STR.repeat(10); @@ -363,7 +407,7 @@ fn test_headers() { let mut srv = TestServer::new(move || { let data = data.clone(); - h1::H1Service::new(move |_| { + HttpService::build().h1(move |_| { let mut builder = Response::Ok(); for idx in 0..90 { builder.header( @@ -384,9 +428,8 @@ fn test_headers() { ); } future::ok::<_, ()>(builder.body(data.clone())) - }).map(|_| ()) + }) }); - let mut connector = srv.new_connector(); let req = srv.get().finish().unwrap(); @@ -399,6 +442,52 @@ fn test_headers() { assert_eq!(bytes, Bytes::from(data2)); } +#[test] +fn test_h2_headers() { + let data = STR.repeat(10); + let data2 = data.clone(); + let openssl = ssl_acceptor().unwrap(); + + let mut srv = TestServer::new(move || { + let data = data.clone(); + openssl + .clone() + .map_err(|e| println!("Openssl error: {}", e)) + .and_then( + HttpService::build().h2(move |_| { + let mut builder = Response::Ok(); + for idx in 0..90 { + builder.header( + format!("X-TEST-{}", idx).as_str(), + "TEST TEST TEST TEST TEST TEST TEST TEST TEST TEST TEST TEST TEST TEST TEST \ + TEST TEST TEST TEST TEST TEST TEST TEST TEST TEST TEST TEST TEST TEST TEST \ + TEST TEST TEST TEST TEST TEST TEST TEST TEST TEST TEST TEST TEST TEST TEST \ + TEST TEST TEST TEST TEST TEST TEST TEST TEST TEST TEST TEST TEST TEST TEST \ + TEST TEST TEST TEST TEST TEST TEST TEST TEST TEST TEST TEST TEST TEST TEST \ + TEST TEST TEST TEST TEST TEST TEST TEST TEST TEST TEST TEST TEST TEST TEST \ + TEST TEST TEST TEST TEST TEST TEST TEST TEST TEST TEST TEST TEST TEST TEST \ + TEST TEST TEST TEST TEST TEST TEST TEST TEST TEST TEST TEST TEST TEST TEST \ + TEST TEST TEST TEST TEST TEST TEST TEST TEST TEST TEST TEST TEST TEST TEST \ + TEST TEST TEST TEST TEST TEST TEST TEST TEST TEST TEST TEST TEST TEST TEST \ + TEST TEST TEST TEST TEST TEST TEST TEST TEST TEST TEST TEST TEST TEST TEST \ + TEST TEST TEST TEST TEST TEST TEST TEST TEST TEST TEST TEST TEST TEST TEST \ + TEST TEST TEST TEST TEST TEST TEST TEST TEST TEST TEST TEST TEST TEST ", + ); + } + future::ok::<_, ()>(builder.body(data.clone())) + }).map_err(|_| ())) + }); + let mut connector = srv.new_connector(); + + let req = client::ClientRequest::get(srv.surl("/")).finish().unwrap(); + let mut response = srv.block_on(req.send(&mut connector)).unwrap(); + assert!(response.status().is_success()); + + // read response + let bytes = srv.block_on(response.body()).unwrap(); + assert_eq!(bytes, Bytes::from(data2)); +} + const STR: &str = "Hello World Hello World Hello World Hello World Hello World \ Hello World Hello World Hello World Hello World Hello World \ Hello World Hello World Hello World Hello World Hello World \ @@ -424,7 +513,7 @@ const STR: &str = "Hello World Hello World Hello World Hello World Hello World \ #[test] fn test_body() { let mut srv = TestServer::new(|| { - h1::H1Service::new(|_| future::ok::<_, ()>(Response::Ok().body(STR))).map(|_| ()) + HttpService::build().h1(|_| future::ok::<_, ()>(Response::Ok().body(STR))) }); let req = srv.get().finish().unwrap(); @@ -439,7 +528,7 @@ fn test_body() { #[test] fn test_head_empty() { let mut srv = TestServer::new(|| { - h1::H1Service::new(|_| ok::<_, ()>(Response::Ok().body(STR))).map(|_| ()) + HttpService::build().h1(|_| ok::<_, ()>(Response::Ok().body(STR))) }); let req = client::ClientRequest::head(srv.url("/")).finish().unwrap(); @@ -462,10 +551,9 @@ fn test_head_empty() { #[test] fn test_head_binary() { let mut srv = TestServer::new(|| { - h1::H1Service::new(|_| { + HttpService::build().h1(|_| { ok::<_, ()>(Response::Ok().content_length(STR.len() as u64).body(STR)) }) - .map(|_| ()) }); let req = client::ClientRequest::head(srv.url("/")).finish().unwrap(); @@ -488,7 +576,7 @@ fn test_head_binary() { #[test] fn test_head_binary2() { let mut srv = TestServer::new(|| { - h1::H1Service::new(|_| ok::<_, ()>(Response::Ok().body(STR))).map(|_| ()) + HttpService::build().h1(|_| ok::<_, ()>(Response::Ok().body(STR))) }); let req = client::ClientRequest::head(srv.url("/")).finish().unwrap(); @@ -507,14 +595,13 @@ fn test_head_binary2() { #[test] fn test_body_length() { let mut srv = TestServer::new(|| { - h1::H1Service::new(|_| { + HttpService::build().h1(|_| { let body = once(Ok(Bytes::from_static(STR.as_ref()))); ok::<_, ()>( Response::Ok() .body(Body::from_message(body::SizedStream::new(STR.len(), body))), ) }) - .map(|_| ()) }); let req = srv.get().finish().unwrap(); @@ -529,11 +616,10 @@ fn test_body_length() { #[test] fn test_body_chunked_explicit() { let mut srv = TestServer::new(|| { - h1::H1Service::new(|_| { + HttpService::build().h1(|_| { let body = once::<_, Error>(Ok(Bytes::from_static(STR.as_ref()))); ok::<_, ()>(Response::Ok().streaming(body)) }) - .map(|_| ()) }); let req = srv.get().finish().unwrap(); @@ -550,7 +636,7 @@ fn test_body_chunked_explicit() { #[test] fn test_body_chunked_implicit() { let mut srv = TestServer::new(|| { - h1::H1Service::new(|_| { + HttpService::build().h1(|_| { let body = once::<_, Error>(Ok(Bytes::from_static(STR.as_ref()))); ok::<_, ()>(Response::Ok().streaming(body)) }) @@ -571,7 +657,7 @@ use actix_service::fn_cfg_factory; #[test] fn test_response_http_error_handling() { let mut srv = TestServer::new(|| { - h1::H1Service::new(fn_cfg_factory(|_: &ServerConfig| { + HttpService::build().h1(fn_cfg_factory(|_: &ServerConfig| { Ok::<_, ()>(|_| { let broken_header = Bytes::from_static(b"\0\0\0"); ok::<_, ()>(