pub mod http_app;
pub mod prometheus_http_app;
use crate::server::ShutdownWatch;
use async_trait::async_trait;
use log::{debug, error};
use std::sync::Arc;
use crate::protocols::http::v2::server;
use crate::protocols::http::ServerSession;
use crate::protocols::Digest;
use crate::protocols::Stream;
use crate::protocols::ALPN;
#[cfg_attr(not(doc_async_trait), async_trait)]
pub trait ServerApp {
async fn process_new(
self: &Arc<Self>,
mut session: Stream,
shutdown: &ShutdownWatch,
) -> Option<Stream>;
async fn cleanup(&self) {}
}
#[cfg_attr(not(doc_async_trait), async_trait)]
pub trait HttpServerApp {
async fn process_new_http(
self: &Arc<Self>,
mut session: ServerSession,
shutdown: &ShutdownWatch,
) -> Option<Stream>;
fn h2_options(&self) -> Option<server::H2Options> {
None
}
async fn http_cleanup(&self) {}
}
#[cfg_attr(not(doc_async_trait), async_trait)]
impl<T> ServerApp for T
where
T: HttpServerApp + Send + Sync + 'static,
{
async fn process_new(
self: &Arc<Self>,
stream: Stream,
shutdown: &ShutdownWatch,
) -> Option<Stream> {
match stream.selected_alpn_proto() {
Some(ALPN::H2) => {
let digest = Arc::new(Digest {
ssl_digest: stream.get_ssl_digest(),
timing_digest: stream.get_timing_digest(),
proxy_digest: stream.get_proxy_digest(),
socket_digest: stream.get_socket_digest(),
});
let h2_options = self.h2_options();
let h2_conn = server::handshake(stream, h2_options).await;
let mut h2_conn = match h2_conn {
Err(e) => {
error!("H2 handshake error {e}");
return None;
}
Ok(c) => c,
};
loop {
let h2_stream =
server::HttpSession::from_h2_conn(&mut h2_conn, digest.clone()).await;
let h2_stream = match h2_stream {
Err(e) => {
debug!("H2 error when accepting new stream {e}");
return None;
}
Ok(s) => s?, };
let app = self.clone();
let shutdown = shutdown.clone();
pingora_runtime::current_handle().spawn(async move {
app.process_new_http(ServerSession::new_http2(h2_stream), &shutdown)
.await;
});
}
}
_ => {
self.process_new_http(ServerSession::new_http1(stream), shutdown)
.await
}
}
}
async fn cleanup(&self) {
self.http_cleanup().await;
}
}