2019-04-06 01:46:44 +02:00
|
|
|
use std::fmt;
|
2019-03-09 19:39:06 +01:00
|
|
|
use std::marker::PhantomData;
|
|
|
|
|
|
|
|
use actix_server_config::ServerConfig as SrvConfig;
|
2019-04-04 19:59:34 +02:00
|
|
|
use actix_service::{IntoNewService, NewService, Service};
|
2019-03-09 19:39:06 +01:00
|
|
|
|
|
|
|
use crate::body::MessageBody;
|
|
|
|
use crate::config::{KeepAlive, ServiceConfig};
|
2019-04-06 01:46:44 +02:00
|
|
|
use crate::error::Error;
|
|
|
|
use crate::h1::{ExpectHandler, H1Service};
|
|
|
|
use crate::h2::H2Service;
|
2019-03-09 19:39:06 +01:00
|
|
|
use crate::request::Request;
|
|
|
|
use crate::response::Response;
|
|
|
|
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.
|
2019-04-06 01:46:44 +02:00
|
|
|
pub struct HttpServiceBuilder<T, S, X = ExpectHandler> {
|
2019-03-09 19:39:06 +01:00
|
|
|
keep_alive: KeepAlive,
|
|
|
|
client_timeout: u64,
|
|
|
|
client_disconnect: u64,
|
2019-04-06 01:46:44 +02:00
|
|
|
expect: X,
|
2019-03-09 19:39:06 +01:00
|
|
|
_t: PhantomData<(T, S)>,
|
|
|
|
}
|
|
|
|
|
2019-04-06 01:46:44 +02:00
|
|
|
impl<T, S> HttpServiceBuilder<T, S, ExpectHandler>
|
2019-03-09 19:39:06 +01:00
|
|
|
where
|
|
|
|
S: NewService<SrvConfig, Request = Request>,
|
2019-04-06 01:46:44 +02:00
|
|
|
S::Error: Into<Error>,
|
|
|
|
S::InitError: fmt::Debug,
|
2019-03-09 19:39:06 +01:00
|
|
|
{
|
|
|
|
/// Create instance of `ServiceConfigBuilder`
|
2019-04-06 01:46:44 +02:00
|
|
|
pub fn new() -> Self {
|
2019-03-09 19:39:06 +01:00
|
|
|
HttpServiceBuilder {
|
|
|
|
keep_alive: KeepAlive::Timeout(5),
|
|
|
|
client_timeout: 5000,
|
|
|
|
client_disconnect: 0,
|
2019-04-06 01:46:44 +02:00
|
|
|
expect: ExpectHandler,
|
2019-03-09 19:39:06 +01:00
|
|
|
_t: PhantomData,
|
|
|
|
}
|
|
|
|
}
|
2019-04-06 01:46:44 +02:00
|
|
|
}
|
2019-03-09 19:39:06 +01:00
|
|
|
|
2019-04-06 01:46:44 +02:00
|
|
|
impl<T, S, X> HttpServiceBuilder<T, S, X>
|
|
|
|
where
|
|
|
|
S: NewService<SrvConfig, Request = Request>,
|
|
|
|
S::Error: Into<Error>,
|
|
|
|
S::InitError: fmt::Debug,
|
|
|
|
X: NewService<Request = Request, Response = Request>,
|
|
|
|
X::Error: Into<Error>,
|
|
|
|
X::InitError: fmt::Debug,
|
|
|
|
{
|
2019-03-09 19:39:06 +01:00
|
|
|
/// 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.
|
|
|
|
///
|
2019-03-09 22:38:56 +01:00
|
|
|
/// By default disconnect timeout is set to 0.
|
2019-03-09 19:39:06 +01:00
|
|
|
pub fn client_disconnect(mut self, val: u64) -> Self {
|
|
|
|
self.client_disconnect = val;
|
|
|
|
self
|
|
|
|
}
|
|
|
|
|
2019-04-08 19:31:29 +02:00
|
|
|
/// Provide service for `EXPECT: 100-Continue` support.
|
|
|
|
///
|
|
|
|
/// Service get called with request that contains `EXPECT` header.
|
|
|
|
/// Service must return request in case of success, in that case
|
|
|
|
/// request will be forwarded to main service.
|
|
|
|
pub fn expect<F, U>(self, expect: F) -> HttpServiceBuilder<T, S, U>
|
|
|
|
where
|
|
|
|
F: IntoNewService<U>,
|
|
|
|
U: NewService<Request = Request, Response = Request>,
|
|
|
|
U::Error: Into<Error>,
|
|
|
|
U::InitError: fmt::Debug,
|
|
|
|
{
|
|
|
|
HttpServiceBuilder {
|
|
|
|
keep_alive: self.keep_alive,
|
|
|
|
client_timeout: self.client_timeout,
|
|
|
|
client_disconnect: self.client_disconnect,
|
|
|
|
expect: expect.into_new_service(),
|
|
|
|
_t: PhantomData,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-03-09 19:39:06 +01:00
|
|
|
// #[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.
|
2019-04-06 01:46:44 +02:00
|
|
|
pub fn h1<F, P, B>(self, service: F) -> H1Service<T, P, S, B, X>
|
2019-03-09 19:39:06 +01:00
|
|
|
where
|
|
|
|
B: MessageBody + 'static,
|
|
|
|
F: IntoNewService<S, SrvConfig>,
|
2019-04-06 01:46:44 +02:00
|
|
|
S::Error: Into<Error>,
|
|
|
|
S::InitError: fmt::Debug,
|
2019-03-09 19:39:06 +01:00
|
|
|
S::Response: Into<Response<B>>,
|
|
|
|
{
|
|
|
|
let cfg = ServiceConfig::new(
|
|
|
|
self.keep_alive,
|
|
|
|
self.client_timeout,
|
|
|
|
self.client_disconnect,
|
|
|
|
);
|
2019-04-06 01:46:44 +02:00
|
|
|
H1Service::with_config(cfg, service.into_new_service()).expect(self.expect)
|
2019-03-09 19:39:06 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
/// Finish service configuration and create *http service* for HTTP/2 protocol.
|
2019-03-11 23:09:42 +01:00
|
|
|
pub fn h2<F, P, B>(self, service: F) -> H2Service<T, P, S, B>
|
2019-03-09 19:39:06 +01:00
|
|
|
where
|
|
|
|
B: MessageBody + 'static,
|
|
|
|
F: IntoNewService<S, SrvConfig>,
|
2019-04-06 01:46:44 +02:00
|
|
|
S::Error: Into<Error>,
|
|
|
|
S::InitError: fmt::Debug,
|
2019-03-09 19:39:06 +01:00
|
|
|
S::Response: Into<Response<B>>,
|
2019-04-04 19:59:34 +02:00
|
|
|
<S::Service as Service>::Future: 'static,
|
2019-03-09 19:39:06 +01:00
|
|
|
{
|
|
|
|
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.
|
2019-04-08 19:31:29 +02:00
|
|
|
pub fn finish<F, P, B>(self, service: F) -> HttpService<T, P, S, B, X>
|
2019-03-09 19:39:06 +01:00
|
|
|
where
|
|
|
|
B: MessageBody + 'static,
|
|
|
|
F: IntoNewService<S, SrvConfig>,
|
2019-04-06 01:46:44 +02:00
|
|
|
S::Error: Into<Error>,
|
|
|
|
S::InitError: fmt::Debug,
|
2019-03-09 19:39:06 +01:00
|
|
|
S::Response: Into<Response<B>>,
|
2019-04-04 19:59:34 +02:00
|
|
|
<S::Service as Service>::Future: 'static,
|
2019-03-09 19:39:06 +01:00
|
|
|
{
|
|
|
|
let cfg = ServiceConfig::new(
|
|
|
|
self.keep_alive,
|
|
|
|
self.client_timeout,
|
|
|
|
self.client_disconnect,
|
|
|
|
);
|
2019-04-08 19:31:29 +02:00
|
|
|
HttpService::with_config(cfg, service.into_new_service()).expect(self.expect)
|
2019-03-09 19:39:06 +01:00
|
|
|
}
|
|
|
|
}
|