1
0
Fork 0
mirror of https://github.com/actix/actix-web.git synced 2024-12-30 12:00:38 +00:00

unify service builders

This commit is contained in:
Nikolay Kim 2019-03-09 10:39:06 -08:00
parent ca73f178c9
commit d026821924
11 changed files with 300 additions and 619 deletions

View file

@ -1,9 +1,8 @@
use std::{env, io}; use std::{env, io};
use actix_http::HttpMessage; use actix_http::HttpMessage;
use actix_http::{h1, Request, Response}; use actix_http::{HttpService, Request, Response};
use actix_server::Server; use actix_server::Server;
use actix_service::NewService;
use bytes::Bytes; use bytes::Bytes;
use futures::Future; use futures::Future;
use http::header::HeaderValue; use http::header::HeaderValue;
@ -15,10 +14,9 @@ fn main() -> io::Result<()> {
Server::build() Server::build()
.bind("echo", "127.0.0.1:8080", || { .bind("echo", "127.0.0.1:8080", || {
h1::H1Service::build() HttpService::build()
.client_timeout(1000) .client_timeout(1000)
.client_disconnect(1000) .client_disconnect(1000)
.server_hostname("localhost")
.finish(|mut req: Request| { .finish(|mut req: Request| {
req.body().limit(512).and_then(|bytes: Bytes| { req.body().limit(512).and_then(|bytes: Bytes| {
info!("request body: {:?}", bytes); info!("request body: {:?}", bytes);
@ -27,7 +25,6 @@ fn main() -> io::Result<()> {
Ok(res.body(bytes)) Ok(res.body(bytes))
}) })
}) })
.map(|_| ())
})? })?
.run() .run()
} }

View file

@ -2,9 +2,8 @@ use std::{env, io};
use actix_http::http::HeaderValue; use actix_http::http::HeaderValue;
use actix_http::HttpMessage; use actix_http::HttpMessage;
use actix_http::{h1, Error, Request, Response}; use actix_http::{Error, HttpService, Request, Response};
use actix_server::Server; use actix_server::Server;
use actix_service::NewService;
use bytes::Bytes; use bytes::Bytes;
use futures::Future; use futures::Future;
use log::info; use log::info;
@ -24,12 +23,7 @@ fn main() -> io::Result<()> {
Server::build() Server::build()
.bind("echo", "127.0.0.1:8080", || { .bind("echo", "127.0.0.1:8080", || {
h1::H1Service::build() HttpService::build().finish(|_req: Request| handle_request(_req))
.client_timeout(1000)
.client_disconnect(1000)
.server_hostname("localhost")
.finish(|_req: Request| handle_request(_req))
.map(|_| ())
})? })?
.run() .run()
} }

View file

@ -1,8 +1,7 @@
use std::{env, io}; use std::{env, io};
use actix_http::{h1, Response}; use actix_http::{HttpService, Response};
use actix_server::Server; use actix_server::Server;
use actix_service::NewService;
use futures::future; use futures::future;
use http::header::HeaderValue; use http::header::HeaderValue;
use log::info; use log::info;
@ -13,17 +12,15 @@ fn main() -> io::Result<()> {
Server::build() Server::build()
.bind("hello-world", "127.0.0.1:8080", || { .bind("hello-world", "127.0.0.1:8080", || {
h1::H1Service::build() HttpService::build()
.client_timeout(1000) .client_timeout(1000)
.client_disconnect(1000) .client_disconnect(1000)
.server_hostname("localhost")
.finish(|_req| { .finish(|_req| {
info!("{:?}", _req); info!("{:?}", _req);
let mut res = Response::Ok(); let mut res = Response::Ok();
res.header("x-head", HeaderValue::from_static("dummy value!")); res.header("x-head", HeaderValue::from_static("dummy value!"));
future::ok::<_, ()>(res.body("Hello world!")) future::ok::<_, ()>(res.body("Hello world!"))
}) })
.map(|_| ())
})? })?
.run() .run()
} }

141
src/builder.rs Normal file
View file

@ -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<T, S> {
keep_alive: KeepAlive,
client_timeout: u64,
client_disconnect: u64,
_t: PhantomData<(T, S)>,
}
impl<T, S> HttpServiceBuilder<T, S>
where
S: NewService<SrvConfig, Request = Request>,
S::Error: Debug + 'static,
S::Service: 'static,
{
/// Create instance of `ServiceConfigBuilder`
pub fn new() -> HttpServiceBuilder<T, S> {
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<U: Into<KeepAlive>>(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<F, B>(self, service: F) -> H1Service<T, S, B>
where
B: MessageBody + 'static,
F: IntoNewService<S, SrvConfig>,
S::Response: Into<Response<B>>,
{
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<F, B>(self, service: F) -> H2Service<T, S, B>
where
B: MessageBody + 'static,
F: IntoNewService<S, SrvConfig>,
S::Response: Into<Response<B>>,
{
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<F, B>(self, service: F) -> HttpService<T, S, B>
where
B: MessageBody + 'static,
F: IntoNewService<S, SrvConfig>,
S::Response: Into<Response<B>>,
{
let cfg = ServiceConfig::new(
self.keep_alive,
self.client_timeout,
self.client_disconnect,
);
HttpService::with_config(cfg, service.into_new_service())
}
}

View file

@ -1,12 +1,11 @@
use std::cell::UnsafeCell; use std::cell::UnsafeCell;
use std::fmt;
use std::fmt::Write; use std::fmt::Write;
use std::rc::Rc; use std::rc::Rc;
use std::time::{Duration, Instant}; use std::time::{Duration, Instant};
use std::{fmt, net};
use bytes::BytesMut; use bytes::BytesMut;
use futures::{future, Future}; use futures::{future, Future};
use log::error;
use time; use time;
use tokio_timer::{sleep, Delay}; use tokio_timer::{sleep, Delay};
@ -90,11 +89,6 @@ impl ServiceConfig {
})) }))
} }
/// Create worker settings builder.
pub fn build() -> ServiceConfigBuilder {
ServiceConfigBuilder::new()
}
#[inline] #[inline]
/// Keep alive duration if configured. /// Keep alive duration if configured.
pub fn keep_alive(&self) -> Option<Duration> { pub fn keep_alive(&self) -> Option<Duration> {
@ -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<T: Into<KeepAlive>>(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<S: net::ToSocketAddrs>(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 { struct Date {
bytes: [u8; DATE_VALUE_LENGTH], bytes: [u8; DATE_VALUE_LENGTH],
pos: usize, pos: usize,

View file

@ -1,6 +1,5 @@
use std::fmt::Debug; use std::fmt::Debug;
use std::marker::PhantomData; use std::marker::PhantomData;
use std::net;
use actix_codec::{AsyncRead, AsyncWrite, Framed}; use actix_codec::{AsyncRead, AsyncWrite, Framed};
use actix_server_config::ServerConfig as SrvConfig; use actix_server_config::ServerConfig as SrvConfig;
@ -8,7 +7,6 @@ use actix_service::{IntoNewService, NewService, Service};
use actix_utils::cloneable::CloneableService; use actix_utils::cloneable::CloneableService;
use futures::future::{ok, FutureResult}; use futures::future::{ok, FutureResult};
use futures::{try_ready, Async, Future, IntoFuture, Poll, Stream}; use futures::{try_ready, Async, Future, IntoFuture, Poll, Stream};
use log::error;
use crate::body::MessageBody; use crate::body::MessageBody;
use crate::config::{KeepAlive, ServiceConfig}; use crate::config::{KeepAlive, ServiceConfig};
@ -57,11 +55,6 @@ where
_t: PhantomData, _t: PhantomData,
} }
} }
/// Create builder for `HttpService` instance.
pub fn build() -> H1ServiceBuilder<T, S> {
H1ServiceBuilder::new()
}
} }
impl<T, S, B> NewService<SrvConfig> for H1Service<T, S, B> impl<T, S, B> NewService<SrvConfig> for H1Service<T, S, B>
@ -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<T, S> {
keep_alive: KeepAlive,
client_timeout: u64,
client_disconnect: u64,
host: String,
addr: net::SocketAddr,
secure: bool,
_t: PhantomData<(T, S)>,
}
impl<T, S> H1ServiceBuilder<T, S>
where
S: NewService<SrvConfig, Request = Request>,
S::Error: Debug,
{
/// Create instance of `ServiceConfigBuilder`
pub fn new() -> H1ServiceBuilder<T, S> {
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<U: Into<KeepAlive>>(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<U: net::ToSocketAddrs>(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<F, B>(self, service: F) -> H1Service<T, S, B>
where
B: MessageBody,
F: IntoNewService<S, SrvConfig>,
{
let cfg = ServiceConfig::new(
self.keep_alive,
self.client_timeout,
self.client_disconnect,
);
H1Service {
cfg,
srv: service.into_new_service(),
_t: PhantomData,
}
}
}
#[doc(hidden)] #[doc(hidden)]
pub struct H1ServiceResponse<T, S: NewService<SrvConfig, Request = Request>, B> { pub struct H1ServiceResponse<T, S: NewService<SrvConfig, Request = Request>, B> {
fut: <S::Future as IntoFuture>::Future, fut: <S::Future as IntoFuture>::Future,

View file

@ -59,11 +59,6 @@ where
_t: PhantomData, _t: PhantomData,
} }
} }
/// Create builder for `HttpService` instance.
pub fn build() -> H2ServiceBuilder<T, S> {
H2ServiceBuilder::new()
}
} }
impl<T, S, B> NewService<SrvConfig> for H2Service<T, S, B> impl<T, S, B> NewService<SrvConfig> for H2Service<T, S, B>
@ -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<T, S> {
keep_alive: KeepAlive,
client_timeout: u64,
client_disconnect: u64,
host: String,
addr: net::SocketAddr,
secure: bool,
_t: PhantomData<(T, S)>,
}
impl<T, S> H2ServiceBuilder<T, S>
where
S: NewService<SrvConfig, Request = Request>,
S::Service: 'static,
S::Error: Debug + 'static,
{
/// Create instance of `H2ServiceBuilder`
pub fn new() -> H2ServiceBuilder<T, S> {
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<U: Into<KeepAlive>>(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<U: net::ToSocketAddrs>(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<F, B>(self, service: F) -> H2Service<T, S, B>
where
B: MessageBody,
F: IntoNewService<S, SrvConfig>,
{
let cfg = ServiceConfig::new(
self.keep_alive,
self.client_timeout,
self.client_disconnect,
);
H2Service {
cfg,
srv: service.into_new_service(),
_t: PhantomData,
}
}
}
#[doc(hidden)] #[doc(hidden)]
pub struct H2ServiceResponse<T, S: NewService<SrvConfig, Request = Request>, B> { pub struct H2ServiceResponse<T, S: NewService<SrvConfig, Request = Request>, B> {
fut: <S::Future as IntoFuture>::Future, fut: <S::Future as IntoFuture>::Future,

View file

@ -69,6 +69,7 @@
extern crate log; extern crate log;
pub mod body; pub mod body;
mod builder;
pub mod client; pub mod client;
mod config; mod config;
mod extensions; mod extensions;
@ -89,7 +90,8 @@ pub mod h2;
pub mod test; pub mod test;
pub mod ws; 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::error::{Error, ResponseError, Result};
pub use self::extensions::Extensions; pub use self::extensions::Extensions;
pub use self::httpmessage::HttpMessage; pub use self::httpmessage::HttpMessage;

View file

@ -1,6 +1,6 @@
use std::fmt::Debug; use std::fmt::Debug;
use std::marker::PhantomData; use std::marker::PhantomData;
use std::{fmt, io, net}; use std::{fmt, io};
use actix_codec::{AsyncRead, AsyncWrite, Framed, FramedParts}; use actix_codec::{AsyncRead, AsyncWrite, Framed, FramedParts};
use actix_server_config::ServerConfig as SrvConfig; use actix_server_config::ServerConfig as SrvConfig;
@ -12,11 +12,11 @@ use h2::server::{self, Handshake};
use log::error; use log::error;
use crate::body::MessageBody; use crate::body::MessageBody;
use crate::builder::HttpServiceBuilder;
use crate::config::{KeepAlive, ServiceConfig}; use crate::config::{KeepAlive, ServiceConfig};
use crate::error::DispatchError; use crate::error::DispatchError;
use crate::request::Request; use crate::request::Request;
use crate::response::Response; use crate::response::Response;
use crate::{h1, h2::Dispatcher}; use crate::{h1, h2::Dispatcher};
/// `NewService` HTTP1.1/HTTP2 transport implementation /// `NewService` HTTP1.1/HTTP2 transport implementation
@ -46,7 +46,7 @@ where
} }
/// Create new `HttpService` instance with config. /// Create new `HttpService` instance with config.
pub fn with_config<F: IntoNewService<S, SrvConfig>>( pub(crate) fn with_config<F: IntoNewService<S, SrvConfig>>(
cfg: ServiceConfig, cfg: ServiceConfig,
service: F, service: F,
) -> Self { ) -> 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<T, S> {
keep_alive: KeepAlive,
client_timeout: u64,
client_disconnect: u64,
host: String,
addr: net::SocketAddr,
secure: bool,
_t: PhantomData<(T, S)>,
}
impl<T, S> HttpServiceBuilder<T, S>
where
S: NewService<SrvConfig, Request = Request>,
S::Service: 'static,
S::Error: Debug + 'static,
{
/// Create instance of `HttpServiceBuilder` type
pub fn new() -> HttpServiceBuilder<T, S> {
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<U: Into<KeepAlive>>(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<U: net::ToSocketAddrs>(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<F, B>(self, service: F) -> HttpService<T, S, B>
where
B: MessageBody,
F: IntoNewService<S, SrvConfig>,
{
let cfg = ServiceConfig::new(
self.keep_alive,
self.client_timeout,
self.client_disconnect,
);
HttpService {
cfg,
srv: service.into_new_service(),
_t: PhantomData,
}
}
}
#[doc(hidden)] #[doc(hidden)]
pub struct HttpServiceResponse<T, S: NewService<SrvConfig>, B> { pub struct HttpServiceResponse<T, S: NewService<SrvConfig>, B> {
fut: <S::Future as IntoFuture>::Future, fut: <S::Future as IntoFuture>::Future,

View file

@ -3,7 +3,7 @@ use bytes::Bytes;
use futures::future::{self, ok}; use futures::future::{self, ok};
use actix_http::HttpMessage; use actix_http::HttpMessage;
use actix_http::{client, h1, Request, Response}; use actix_http::{client, HttpService, Request, Response};
use actix_http_test::TestServer; use actix_http_test::TestServer;
const STR: &str = "Hello World Hello World Hello World Hello World Hello World \ 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() { fn test_h1_v2() {
env_logger::init(); env_logger::init();
let mut srv = TestServer::new(move || { let mut srv = TestServer::new(move || {
h1::H1Service::build() HttpService::build()
.finish(|_| future::ok::<_, ()>(Response::Ok().body(STR))) .finish(|_| future::ok::<_, ()>(Response::Ok().body(STR)))
.map(|_| ()) .map(|_| ())
}); });
@ -66,7 +66,7 @@ fn test_h1_v2() {
#[test] #[test]
fn test_connection_close() { fn test_connection_close() {
let mut srv = TestServer::new(move || { let mut srv = TestServer::new(move || {
h1::H1Service::build() HttpService::build()
.finish(|_| ok::<_, ()>(Response::Ok().body(STR))) .finish(|_| ok::<_, ()>(Response::Ok().body(STR)))
.map(|_| ()) .map(|_| ())
}); });
@ -80,7 +80,7 @@ fn test_connection_close() {
#[test] #[test]
fn test_with_query_parameter() { fn test_with_query_parameter() {
let mut srv = TestServer::new(move || { let mut srv = TestServer::new(move || {
h1::H1Service::build() HttpService::build()
.finish(|req: Request| { .finish(|req: Request| {
if req.uri().query().unwrap().contains("qp=") { if req.uri().query().unwrap().contains("qp=") {
ok::<_, ()>(Response::Ok().finish()) ok::<_, ()>(Response::Ok().finish())

View file

@ -10,20 +10,18 @@ use futures::stream::once;
use actix_http::body::Body; use actix_http::body::Body;
use actix_http::{ use actix_http::{
body, client, h1, h2, http, Error, HttpMessage as HttpMessage2, HttpService, body, client, http, Error, HttpMessage as HttpMessage2, HttpService, KeepAlive,
KeepAlive, Request, Response, Request, Response,
}; };
#[test] #[test]
fn test_h1() { fn test_h1() {
let mut srv = TestServer::new(|| { let mut srv = TestServer::new(|| {
h1::H1Service::build() HttpService::build()
.keep_alive(KeepAlive::Disabled) .keep_alive(KeepAlive::Disabled)
.client_timeout(1000) .client_timeout(1000)
.client_disconnect(1000) .client_disconnect(1000)
.server_hostname("localhost") .h1(|_| future::ok::<_, ()>(Response::Ok().finish()))
.finish(|_| future::ok::<_, ()>(Response::Ok().finish()))
.map(|_| ())
}); });
let req = client::ClientRequest::get(srv.url("/")).finish().unwrap(); let req = client::ClientRequest::get(srv.url("/")).finish().unwrap();
@ -38,7 +36,6 @@ fn test_h1_2() {
.keep_alive(KeepAlive::Disabled) .keep_alive(KeepAlive::Disabled)
.client_timeout(1000) .client_timeout(1000)
.client_disconnect(1000) .client_disconnect(1000)
.server_hostname("localhost")
.finish(|req: Request| { .finish(|req: Request| {
assert_eq!(req.version(), http::Version::HTTP_11); assert_eq!(req.version(), http::Version::HTTP_11);
future::ok::<_, ()>(Response::Ok().finish()) future::ok::<_, ()>(Response::Ok().finish())
@ -83,8 +80,8 @@ fn test_h2() -> std::io::Result<()> {
.clone() .clone()
.map_err(|e| println!("Openssl error: {}", e)) .map_err(|e| println!("Openssl error: {}", e))
.and_then( .and_then(
h2::H2Service::build() HttpService::build()
.finish(|_| future::ok::<_, Error>(Response::Ok().finish())) .h2(|_| future::ok::<_, Error>(Response::Ok().finish()))
.map_err(|_| ()), .map_err(|_| ()),
) )
}); });
@ -129,8 +126,8 @@ fn test_h2_body() -> std::io::Result<()> {
.clone() .clone()
.map_err(|e| println!("Openssl error: {}", e)) .map_err(|e| println!("Openssl error: {}", e))
.and_then( .and_then(
h2::H2Service::build() HttpService::build()
.finish(|mut req: Request<_>| { .h2(|mut req: Request<_>| {
req.body() req.body()
.limit(1024 * 1024) .limit(1024 * 1024)
.and_then(|body| Ok(Response::Ok().body(body))) .and_then(|body| Ok(Response::Ok().body(body)))
@ -153,10 +150,9 @@ fn test_h2_body() -> std::io::Result<()> {
#[test] #[test]
fn test_slow_request() { fn test_slow_request() {
let srv = TestServer::new(|| { let srv = TestServer::new(|| {
h1::H1Service::build() HttpService::build()
.client_timeout(100) .client_timeout(100)
.finish(|_| future::ok::<_, ()>(Response::Ok().finish())) .h1(|_| future::ok::<_, ()>(Response::Ok().finish()))
.map(|_| ())
}); });
let mut stream = net::TcpStream::connect(srv.addr()).unwrap(); let mut stream = net::TcpStream::connect(srv.addr()).unwrap();
@ -167,9 +163,9 @@ fn test_slow_request() {
} }
#[test] #[test]
fn test_malformed_request() { fn test_http1_malformed_request() {
let srv = TestServer::new(|| { 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(); let mut stream = net::TcpStream::connect(srv.addr()).unwrap();
@ -180,11 +176,9 @@ fn test_malformed_request() {
} }
#[test] #[test]
fn test_keepalive() { fn test_http1_keepalive() {
let srv = TestServer::new(|| { let srv = TestServer::new(|| {
h1::H1Service::build() HttpService::build().h1(|_| future::ok::<_, ()>(Response::Ok().finish()))
.finish(|_| future::ok::<_, ()>(Response::Ok().finish()))
.map(|_| ())
}); });
let mut stream = net::TcpStream::connect(srv.addr()).unwrap(); let mut stream = net::TcpStream::connect(srv.addr()).unwrap();
@ -200,12 +194,11 @@ fn test_keepalive() {
} }
#[test] #[test]
fn test_keepalive_timeout() { fn test_http1_keepalive_timeout() {
let srv = TestServer::new(|| { let srv = TestServer::new(|| {
h1::H1Service::build() HttpService::build()
.keep_alive(1) .keep_alive(1)
.finish(|_| future::ok::<_, ()>(Response::Ok().finish())) .h1(|_| future::ok::<_, ()>(Response::Ok().finish()))
.map(|_| ())
}); });
let mut stream = net::TcpStream::connect(srv.addr()).unwrap(); let mut stream = net::TcpStream::connect(srv.addr()).unwrap();
@ -221,11 +214,9 @@ fn test_keepalive_timeout() {
} }
#[test] #[test]
fn test_keepalive_close() { fn test_http1_keepalive_close() {
let srv = TestServer::new(|| { let srv = TestServer::new(|| {
h1::H1Service::build() HttpService::build().h1(|_| future::ok::<_, ()>(Response::Ok().finish()))
.finish(|_| future::ok::<_, ()>(Response::Ok().finish()))
.map(|_| ())
}); });
let mut stream = net::TcpStream::connect(srv.addr()).unwrap(); let mut stream = net::TcpStream::connect(srv.addr()).unwrap();
@ -241,11 +232,9 @@ fn test_keepalive_close() {
} }
#[test] #[test]
fn test_keepalive_http10_default_close() { fn test_http10_keepalive_default_close() {
let srv = TestServer::new(|| { let srv = TestServer::new(|| {
h1::H1Service::build() HttpService::build().h1(|_| future::ok::<_, ()>(Response::Ok().finish()))
.finish(|_| future::ok::<_, ()>(Response::Ok().finish()))
.map(|_| ())
}); });
let mut stream = net::TcpStream::connect(srv.addr()).unwrap(); let mut stream = net::TcpStream::connect(srv.addr()).unwrap();
@ -260,11 +249,9 @@ fn test_keepalive_http10_default_close() {
} }
#[test] #[test]
fn test_keepalive_http10() { fn test_http10_keepalive() {
let srv = TestServer::new(|| { let srv = TestServer::new(|| {
h1::H1Service::build() HttpService::build().h1(|_| future::ok::<_, ()>(Response::Ok().finish()))
.finish(|_| future::ok::<_, ()>(Response::Ok().finish()))
.map(|_| ())
}); });
let mut stream = net::TcpStream::connect(srv.addr()).unwrap(); let mut stream = net::TcpStream::connect(srv.addr()).unwrap();
@ -286,12 +273,11 @@ fn test_keepalive_http10() {
} }
#[test] #[test]
fn test_keepalive_disabled() { fn test_http1_keepalive_disabled() {
let srv = TestServer::new(|| { let srv = TestServer::new(|| {
h1::H1Service::build() HttpService::build()
.keep_alive(KeepAlive::Disabled) .keep_alive(KeepAlive::Disabled)
.finish(|_| future::ok::<_, ()>(Response::Ok().finish())) .h1(|_| future::ok::<_, ()>(Response::Ok().finish()))
.map(|_| ())
}); });
let mut stream = net::TcpStream::connect(srv.addr()).unwrap(); let mut stream = net::TcpStream::connect(srv.addr()).unwrap();
@ -313,7 +299,7 @@ fn test_content_length() {
}; };
let mut srv = TestServer::new(|| { 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 indx: usize = req.uri().path()[1..].parse().unwrap();
let statuses = [ let statuses = [
StatusCode::NO_CONTENT, StatusCode::NO_CONTENT,
@ -325,7 +311,6 @@ fn test_content_length() {
]; ];
future::ok::<_, ()>(Response::new(statuses[indx])) future::ok::<_, ()>(Response::new(statuses[indx]))
}) })
.map(|_| ())
}); });
let header = HeaderName::from_static("content-length"); 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] #[test]
fn test_headers() { fn test_headers() {
let data = STR.repeat(10); let data = STR.repeat(10);
@ -363,7 +407,7 @@ fn test_headers() {
let mut srv = TestServer::new(move || { let mut srv = TestServer::new(move || {
let data = data.clone(); let data = data.clone();
h1::H1Service::new(move |_| { HttpService::build().h1(move |_| {
let mut builder = Response::Ok(); let mut builder = Response::Ok();
for idx in 0..90 { for idx in 0..90 {
builder.header( builder.header(
@ -384,9 +428,8 @@ fn test_headers() {
); );
} }
future::ok::<_, ()>(builder.body(data.clone())) future::ok::<_, ()>(builder.body(data.clone()))
}).map(|_| ()) })
}); });
let mut connector = srv.new_connector(); let mut connector = srv.new_connector();
let req = srv.get().finish().unwrap(); let req = srv.get().finish().unwrap();
@ -399,6 +442,52 @@ fn test_headers() {
assert_eq!(bytes, Bytes::from(data2)); 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 \ 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 \
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] #[test]
fn test_body() { fn test_body() {
let mut srv = TestServer::new(|| { 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(); let req = srv.get().finish().unwrap();
@ -439,7 +528,7 @@ fn test_body() {
#[test] #[test]
fn test_head_empty() { fn test_head_empty() {
let mut srv = TestServer::new(|| { 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(); let req = client::ClientRequest::head(srv.url("/")).finish().unwrap();
@ -462,10 +551,9 @@ fn test_head_empty() {
#[test] #[test]
fn test_head_binary() { fn test_head_binary() {
let mut srv = TestServer::new(|| { let mut srv = TestServer::new(|| {
h1::H1Service::new(|_| { HttpService::build().h1(|_| {
ok::<_, ()>(Response::Ok().content_length(STR.len() as u64).body(STR)) ok::<_, ()>(Response::Ok().content_length(STR.len() as u64).body(STR))
}) })
.map(|_| ())
}); });
let req = client::ClientRequest::head(srv.url("/")).finish().unwrap(); let req = client::ClientRequest::head(srv.url("/")).finish().unwrap();
@ -488,7 +576,7 @@ fn test_head_binary() {
#[test] #[test]
fn test_head_binary2() { fn test_head_binary2() {
let mut srv = TestServer::new(|| { 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(); let req = client::ClientRequest::head(srv.url("/")).finish().unwrap();
@ -507,14 +595,13 @@ fn test_head_binary2() {
#[test] #[test]
fn test_body_length() { fn test_body_length() {
let mut srv = TestServer::new(|| { let mut srv = TestServer::new(|| {
h1::H1Service::new(|_| { HttpService::build().h1(|_| {
let body = once(Ok(Bytes::from_static(STR.as_ref()))); let body = once(Ok(Bytes::from_static(STR.as_ref())));
ok::<_, ()>( ok::<_, ()>(
Response::Ok() Response::Ok()
.body(Body::from_message(body::SizedStream::new(STR.len(), body))), .body(Body::from_message(body::SizedStream::new(STR.len(), body))),
) )
}) })
.map(|_| ())
}); });
let req = srv.get().finish().unwrap(); let req = srv.get().finish().unwrap();
@ -529,11 +616,10 @@ fn test_body_length() {
#[test] #[test]
fn test_body_chunked_explicit() { fn test_body_chunked_explicit() {
let mut srv = TestServer::new(|| { let mut srv = TestServer::new(|| {
h1::H1Service::new(|_| { HttpService::build().h1(|_| {
let body = once::<_, Error>(Ok(Bytes::from_static(STR.as_ref()))); let body = once::<_, Error>(Ok(Bytes::from_static(STR.as_ref())));
ok::<_, ()>(Response::Ok().streaming(body)) ok::<_, ()>(Response::Ok().streaming(body))
}) })
.map(|_| ())
}); });
let req = srv.get().finish().unwrap(); let req = srv.get().finish().unwrap();
@ -550,7 +636,7 @@ fn test_body_chunked_explicit() {
#[test] #[test]
fn test_body_chunked_implicit() { fn test_body_chunked_implicit() {
let mut srv = TestServer::new(|| { let mut srv = TestServer::new(|| {
h1::H1Service::new(|_| { HttpService::build().h1(|_| {
let body = once::<_, Error>(Ok(Bytes::from_static(STR.as_ref()))); let body = once::<_, Error>(Ok(Bytes::from_static(STR.as_ref())));
ok::<_, ()>(Response::Ok().streaming(body)) ok::<_, ()>(Response::Ok().streaming(body))
}) })
@ -571,7 +657,7 @@ use actix_service::fn_cfg_factory;
#[test] #[test]
fn test_response_http_error_handling() { fn test_response_http_error_handling() {
let mut srv = TestServer::new(|| { let mut srv = TestServer::new(|| {
h1::H1Service::new(fn_cfg_factory(|_: &ServerConfig| { HttpService::build().h1(fn_cfg_factory(|_: &ServerConfig| {
Ok::<_, ()>(|_| { Ok::<_, ()>(|_| {
let broken_header = Bytes::from_static(b"\0\0\0"); let broken_header = Bytes::from_static(b"\0\0\0");
ok::<_, ()>( ok::<_, ()>(