use crate::endpoint::WitchcraftEndpoint;
use crate::logging::Loggers;
use crate::service::accept::AcceptService;
use crate::service::audit_log::AuditLogLayer;
use crate::service::cancellation::CancellationLayer;
use crate::service::catch_unwind::CatchUnwindLayer;
use crate::service::client_certificate::ClientCertificateLayer;
use crate::service::connection_limit::ConnectionLimitLayer;
use crate::service::connection_metrics::ConnectionMetricsLayer;
use crate::service::deprecation_header::DeprecationHeaderLayer;
use crate::service::endpoint_health::EndpointHealthLayer;
use crate::service::endpoint_metrics::EndpointMetricsLayer;
use crate::service::error_log::ErrorLogLayer;
use crate::service::graceful_shutdown::GracefulShutdownLayer;
use crate::service::gzip::GzipLayer;
use crate::service::handler::HandlerService;
use crate::service::hyper::{HyperService, NewConnection};
use crate::service::idle_connection::IdleConnectionLayer;
use crate::service::keep_alive_header::KeepAliveHeaderLayer;
use crate::service::mdc::MdcLayer;
use crate::service::no_caching::NoCachingLayer;
use crate::service::peer_addr::PeerAddrLayer;
use crate::service::request_id::RequestIdLayer;
use crate::service::request_log::{RequestLogLayer, RequestLogRequestBody};
use crate::service::routing::RoutingLayer;
use crate::service::server_header::ServerHeaderLayer;
use crate::service::server_metrics::ServerMetricsLayer;
use crate::service::server_timing_header::ServerTimingHeaderLayer;
use crate::service::spans::{SpannedBody, SpansLayer};
use crate::service::tls::TlsLayer;
use crate::service::tls_metrics::TlsMetricsLayer;
use crate::service::trace_id_header::TraceIdHeaderLayer;
use crate::service::trace_propagation::TracePropagationLayer;
use crate::service::unverified_jwt::UnverifiedJwtLayer;
use crate::service::web_security::WebSecurityLayer;
use crate::service::witchcraft_mdc::WitchcraftMdcLayer;
use crate::service::{Service, ServiceBuilder};
use crate::Witchcraft;
use conjure_error::Error;
use hyper::body::Incoming;
use std::sync::Arc;
use tokio::task;
use witchcraft_log::debug;
pub type RawBody = RequestLogRequestBody<SpannedBody<Incoming>>;
#[derive(Copy, Clone)]
pub enum Listener {
Service,
Management,
}
impl Listener {
pub fn tag(&self) -> &'static str {
match self {
Listener::Service => "service",
Listener::Management => "management",
}
}
}
pub(crate) async fn start(
witchcraft: &mut Witchcraft,
endpoints: Vec<Box<dyn WitchcraftEndpoint + Sync + Send>>,
loggers: &Loggers,
listener: Listener,
port: u16,
) -> Result<(), Error> {
let request_service = ServiceBuilder::new()
.layer(RoutingLayer::new(endpoints))
.layer(RequestIdLayer)
.layer(TracePropagationLayer)
.layer(SpansLayer)
.layer(UnverifiedJwtLayer)
.layer(MdcLayer)
.layer(WitchcraftMdcLayer)
.layer(RequestLogLayer::new(loggers.request_logger.clone()))
.layer(AuditLogLayer::new(loggers.audit_logger.clone()))
.layer(CancellationLayer)
.layer(GzipLayer::new(&witchcraft.install_config))
.layer(DeprecationHeaderLayer)
.layer(KeepAliveHeaderLayer::new(&witchcraft.install_config))
.layer(ServerHeaderLayer::new(&witchcraft.install_config)?)
.layer(NoCachingLayer)
.layer(WebSecurityLayer)
.layer(TraceIdHeaderLayer)
.layer(ServerTimingHeaderLayer)
.layer(ServerMetricsLayer::new(&witchcraft.metrics, listener))
.layer(EndpointMetricsLayer)
.layer(EndpointHealthLayer)
.layer(ErrorLogLayer)
.layer(CatchUnwindLayer)
.service(HandlerService);
let handle_service = ServiceBuilder::new()
.layer(PeerAddrLayer)
.layer(TlsLayer::new(&witchcraft.install_config)?)
.layer(TlsMetricsLayer::new(&witchcraft.metrics))
.layer(ClientCertificateLayer)
.layer(GracefulShutdownLayer::new(&mut witchcraft.shutdown_hooks))
.layer(IdleConnectionLayer::new(&witchcraft.install_config))
.service(HyperService::new(request_service));
let handle_service = Arc::new(handle_service);
let accept_service = ServiceBuilder::new()
.layer(ConnectionLimitLayer::new(&witchcraft.install_config))
.layer(ConnectionMetricsLayer::new(
&witchcraft.install_config,
&witchcraft.metrics,
listener,
))
.service(AcceptService::new(port)?);
let handle = task::spawn(async move {
loop {
let stream = accept_service.call(()).await;
let connection = NewConnection {
stream,
service_builder: ServiceBuilder::new(),
};
task::spawn({
let handle_service = handle_service.clone();
async move {
if let Err(e) = handle_service.call(connection).await {
debug!("http connection terminated", error: e);
}
}
});
}
});
witchcraft.on_shutdown(async move {
handle.abort();
});
Ok(())
}