use core::{fmt, marker::PhantomData};
use xitca_io::net;
use xitca_service::Service;
use super::{
body::RequestBody,
config::{HttpServiceConfig, DEFAULT_HEADER_LIMIT, DEFAULT_READ_BUF_LIMIT, DEFAULT_WRITE_BUF_LIMIT},
service::HttpService,
tls,
};
#[doc(hidden)]
pub(crate) mod marker {
pub struct Http;
#[cfg(feature = "http1")]
pub struct Http1;
#[cfg(all(feature = "io-uring", feature = "http1"))]
pub struct Http1Uring;
#[cfg(all(feature = "io-uring", feature = "http2"))]
pub struct Http2Uring;
#[cfg(feature = "http2")]
pub struct Http2;
}
pub struct HttpServiceBuilder<
V,
St,
FA,
const HEADER_LIMIT: usize,
const READ_BUF_LIMIT: usize,
const WRITE_BUF_LIMIT: usize,
> {
pub(crate) tls_factory: FA,
pub(crate) config: HttpServiceConfig<HEADER_LIMIT, READ_BUF_LIMIT, WRITE_BUF_LIMIT>,
pub(crate) _body: PhantomData<fn(V, St)>,
}
impl Default
for HttpServiceBuilder<
marker::Http,
net::Stream,
tls::NoOpTlsAcceptorBuilder,
DEFAULT_HEADER_LIMIT,
DEFAULT_READ_BUF_LIMIT,
DEFAULT_WRITE_BUF_LIMIT,
>
{
fn default() -> Self {
unimplemented!("please use HttpServiceBuilder::new")
}
}
impl
HttpServiceBuilder<
marker::Http,
net::Stream,
tls::NoOpTlsAcceptorBuilder,
DEFAULT_HEADER_LIMIT,
DEFAULT_READ_BUF_LIMIT,
DEFAULT_WRITE_BUF_LIMIT,
>
{
pub const fn new() -> Self {
Self::with_config(HttpServiceConfig::new())
}
pub const fn with_config<const HEADER_LIMIT: usize, const READ_BUF_LIMIT: usize, const WRITE_BUF_LIMIT: usize>(
config: HttpServiceConfig<HEADER_LIMIT, READ_BUF_LIMIT, WRITE_BUF_LIMIT>,
) -> HttpServiceBuilder<
marker::Http,
net::Stream,
tls::NoOpTlsAcceptorBuilder,
HEADER_LIMIT,
READ_BUF_LIMIT,
WRITE_BUF_LIMIT,
> {
HttpServiceBuilder {
tls_factory: tls::NoOpTlsAcceptorBuilder,
config,
_body: PhantomData,
}
}
#[cfg(feature = "http1")]
pub fn h1() -> HttpServiceBuilder<
marker::Http1,
net::TcpStream,
tls::NoOpTlsAcceptorBuilder,
DEFAULT_HEADER_LIMIT,
DEFAULT_READ_BUF_LIMIT,
DEFAULT_WRITE_BUF_LIMIT,
> {
HttpServiceBuilder {
tls_factory: tls::NoOpTlsAcceptorBuilder,
config: HttpServiceConfig::default(),
_body: PhantomData,
}
}
#[cfg(feature = "http2")]
pub fn h2() -> HttpServiceBuilder<
marker::Http2,
net::TcpStream,
tls::NoOpTlsAcceptorBuilder,
DEFAULT_HEADER_LIMIT,
DEFAULT_READ_BUF_LIMIT,
DEFAULT_WRITE_BUF_LIMIT,
> {
HttpServiceBuilder {
tls_factory: tls::NoOpTlsAcceptorBuilder,
config: HttpServiceConfig::default(),
_body: PhantomData,
}
}
#[cfg(feature = "http3")]
pub fn h3() -> super::h3::H3ServiceBuilder {
super::h3::H3ServiceBuilder::new()
}
}
impl<V, St, FA, const HEADER_LIMIT: usize, const READ_BUF_LIMIT: usize, const WRITE_BUF_LIMIT: usize>
HttpServiceBuilder<V, St, FA, HEADER_LIMIT, READ_BUF_LIMIT, WRITE_BUF_LIMIT>
{
pub fn config<const HEADER_LIMIT_2: usize, const READ_BUF_LIMIT_2: usize, const WRITE_BUF_LIMIT_2: usize>(
self,
config: HttpServiceConfig<HEADER_LIMIT_2, READ_BUF_LIMIT_2, WRITE_BUF_LIMIT_2>,
) -> HttpServiceBuilder<V, St, FA, HEADER_LIMIT_2, READ_BUF_LIMIT_2, WRITE_BUF_LIMIT_2> {
HttpServiceBuilder {
tls_factory: self.tls_factory,
config,
_body: PhantomData,
}
}
pub fn with_tls<TlsF>(
self,
tls_factory: TlsF,
) -> HttpServiceBuilder<V, St, TlsF, HEADER_LIMIT, READ_BUF_LIMIT, WRITE_BUF_LIMIT> {
HttpServiceBuilder {
tls_factory,
config: self.config,
_body: PhantomData,
}
}
#[cfg(feature = "openssl")]
pub fn openssl(
self,
acceptor: tls::openssl::TlsAcceptor,
) -> HttpServiceBuilder<V, St, tls::openssl::TlsAcceptorBuilder, HEADER_LIMIT, READ_BUF_LIMIT, WRITE_BUF_LIMIT>
{
self.with_tls(tls::openssl::TlsAcceptorBuilder::new(acceptor))
}
#[cfg(feature = "rustls")]
pub fn rustls(
self,
config: tls::rustls::RustlsConfig,
) -> HttpServiceBuilder<V, St, tls::rustls::TlsAcceptorBuilder, HEADER_LIMIT, READ_BUF_LIMIT, WRITE_BUF_LIMIT> {
self.with_tls(tls::rustls::TlsAcceptorBuilder::new(config))
}
#[cfg(feature = "rustls-uring")]
pub fn rustls_uring(
self,
config: tls::rustls::RustlsConfig,
) -> HttpServiceBuilder<V, St, tls::rustls_uring::TlsAcceptorBuilder, HEADER_LIMIT, READ_BUF_LIMIT, WRITE_BUF_LIMIT>
{
self.with_tls(tls::rustls_uring::TlsAcceptorBuilder::new(config))
}
#[cfg(feature = "native-tls")]
pub fn native_tls(
self,
acceptor: tls::native_tls::TlsAcceptor,
) -> HttpServiceBuilder<V, St, tls::native_tls::TlsAcceptorBuilder, HEADER_LIMIT, READ_BUF_LIMIT, WRITE_BUF_LIMIT>
{
self.with_tls(tls::native_tls::TlsAcceptorBuilder::new(acceptor))
}
}
type Error = Box<dyn fmt::Debug>;
impl<FA, S, E, const HEADER_LIMIT: usize, const READ_BUF_LIMIT: usize, const WRITE_BUF_LIMIT: usize>
Service<Result<S, E>>
for HttpServiceBuilder<marker::Http, net::Stream, FA, HEADER_LIMIT, READ_BUF_LIMIT, WRITE_BUF_LIMIT>
where
FA: Service,
FA::Error: fmt::Debug + 'static,
E: fmt::Debug + 'static,
{
type Response =
HttpService<net::Stream, S, RequestBody, FA::Response, HEADER_LIMIT, READ_BUF_LIMIT, WRITE_BUF_LIMIT>;
type Error = Error;
async fn call(&self, res: Result<S, E>) -> Result<Self::Response, Self::Error> {
let service = res.map_err(|e| Box::new(e) as Error)?;
let tls_acceptor = self.tls_factory.call(()).await.map_err(|e| Box::new(e) as Error)?;
Ok(HttpService::new(self.config, service, tls_acceptor))
}
}