Skip to main content

praxis_protocol/http/pingora/
mod.rs

1// SPDX-License-Identifier: Apache-2.0
2// Copyright (c) 2024 Praxis Contributors
3
4//! Pingora HTTP integration: handler, listener setup, health endpoints.
5//!
6//! This module adapts Praxis's filter pipeline to Pingora's HTTP proxy
7//! service. Pingora owns request-smuggling prevention, HTTP/2
8//! backpressure, connection-pool safety, and HTTP/1.1 upgrade detection
9//! with bidirectional forwarding (WebSocket and similar). Praxis code
10//! layered on top, here and in the [`handler`](crate::http::pingora::handler) submodule, owns
11//! hop-by-hop header stripping (with conditional preservation for
12//! upgrade requests), Host validation, `X-Forwarded-*` injection, and
13//! retry logic.
14
15use std::sync::Arc;
16
17use praxis_core::{
18    PingoraServerRuntime, ProxyError,
19    config::{Config, ProtocolKind},
20};
21
22use crate::{ListenerPipelines, Protocol};
23
24/// Per-request context for filter pipeline results.
25pub mod context;
26pub(crate) mod convert;
27/// HTTP proxy handler and Pingora integration.
28pub mod handler;
29/// Health check infrastructure: admin endpoints, probes, and background runner.
30pub mod health;
31#[cfg(feature = "admin-api")]
32pub(crate) mod json;
33/// Admin endpoints for runtime key-value store CRUD.
34#[cfg(feature = "admin-api")]
35pub mod kv;
36/// Listener configuration and TLS setup.
37pub mod listener;
38/// Prometheus metrics: recorder, HTTP request counters, and scrape endpoint.
39pub mod metrics;
40
41// -----------------------------------------------------------------------------
42// PingoraHttp
43// -----------------------------------------------------------------------------
44
45/// Pingora-backed HTTP protocol implementation.
46pub struct PingoraHttp;
47
48impl Protocol for PingoraHttp {
49    fn register(
50        self: Box<Self>,
51        server: &mut PingoraServerRuntime,
52        config: &Config,
53        pipelines: &ListenerPipelines,
54    ) -> Result<Vec<tokio::sync::watch::Sender<bool>>, ProxyError> {
55        let http_listeners: Vec<_> = config
56            .listeners
57            .iter()
58            .filter(|l| l.protocol == ProtocolKind::Http)
59            .collect();
60
61        if http_listeners.is_empty() {
62            return Ok(Vec::new());
63        }
64
65        let mut cert_watcher_shutdowns = Vec::new();
66        for listener in &http_listeners {
67            let pipeline = pipelines.get(&listener.name).map(Arc::clone).ok_or_else(|| {
68                ProxyError::Config(format!("no pipeline for listener '{name}'", name = listener.name))
69            })?;
70
71            handler::load_http_handler(server.server_mut(), listener, pipeline, &mut cert_watcher_shutdowns)?;
72        }
73
74        Ok(cert_watcher_shutdowns)
75    }
76}