Skip to main content

PingoraRequestCtx

Struct PingoraRequestCtx 

Source
pub struct PingoraRequestCtx {
Show 43 fields pub _connection_permit: Option<OwnedSemaphorePermit>, pub _global_connection_permit: Option<OwnedSemaphorePermit>, pub client_addr: Option<IpAddr>, pub client_http_version: Option<Version>, pub cluster: Option<Arc<str>>, pub cached_body_done_indices: Vec<bool>, pub cached_executed_filter_indices: Vec<bool>, pub downstream_tls: bool, pub peer_identity: Option<TlsPeerIdentity>, pub connection_upgraded: bool, pub extensions: RequestExtensions, pub filter_metadata: HashMap<String, String>, pub pre_read_mutations: Vec<TrustedHeaderMutation>, pub structured_metadata: HashMap<String, Value>, pub mutated_request_body_len: Option<usize>, pub pinned_pipeline: Option<Arc<FilterPipeline>>, pub filter_results: HashMap<&'static str, FilterResultSet>, pub filter_state: HashMap<usize, Box<dyn Any + Send + Sync>>, pub metrics_cluster: Option<Arc<str>>, pub metrics_cluster_shared: Option<SharedString>, pub metrics_route: Option<SharedString>, pub upstream_connect_start: Option<Instant>, pub pre_read_body: Option<VecDeque<Bytes>>, pub request_body_buffer: Option<BodyBuffer>, pub request_body_bytes: u64, pub request_body_mode: BodyMode, pub request_body_released: bool, pub request_is_idempotent: bool, pub request_snapshot: Option<Request>, pub request_span: Span, pub request_start: Instant, pub response_body_buffer: Option<BodyBuffer>, pub response_body_bytes: u64, pub response_body_mode: BodyMode, pub response_body_released: bool, pub response_header_snapshot: Option<Response>, pub upstream_response_status: Option<u16>, pub response_phase_done: bool, pub retries: u32, pub selected_endpoint_index: Option<usize>, pub rewritten_path: Option<String>, pub upstream: Option<Upstream>, pub upstream_for_retry: Option<Upstream>, /* private fields */
}
Expand description

Per-request context carrying filter pipeline results through Pingora hooks.

use std::sync::Arc;

use praxis_protocol::http::pingora::context::PingoraRequestCtx;

let mut ctx = PingoraRequestCtx::default();
ctx.cluster = Some(Arc::from("api-cluster"));
assert_eq!(ctx.cluster.as_deref(), Some("api-cluster"));

Fields§

§_connection_permit: Option<OwnedSemaphorePermit>

Connection permit from the per-listener semaphore.

Held for the lifetime of the request. RAII drop releases the permit when the context is dropped, including error and timeout paths.

§_global_connection_permit: Option<OwnedSemaphorePermit>

Permit from the process-wide connection semaphore.

Present only when runtime.max_connections is configured.

§client_addr: Option<IpAddr>

Downstream client IP address.

§client_http_version: Option<Version>

HTTP version of the downstream client request.

Captured during request_filter so the response-phase Via header can reflect the protocol the client used.

§cluster: Option<Arc<str>>

Name of the cluster selected by a cluster-selecting filter.

§cached_body_done_indices: Vec<bool>

Cached per-filter body-done indices. Swapped into each HttpFilterContext and written back after execution so that the heap allocation is reused across pipeline phases.

§cached_executed_filter_indices: Vec<bool>

Cached per-filter execution indices. Same lifecycle as cached_body_done_indices.

§downstream_tls: bool

Whether the downstream connection uses TLS.

Derived from the Pingora session’s SSL digest during request_filter. Used by the forwarded headers filter to set X-Forwarded-Proto correctly for HTTP/1.1 connections where the URI lacks a scheme.

§peer_identity: Option<TlsPeerIdentity>

Verified downstream TLS peer identity.

Set once from the SSL digest in request_filter before the first filter runs. Cloned (not moved) into each HttpFilterContext so it is available in both pre-read body phases and the main filter pipeline. None for non-mTLS or no-client-cert connections.

§connection_upgraded: bool

Whether the connection was upgraded via 101 Switching Protocols.

Set during response_filter when the upstream returns 101. Body filter hooks skip processing when true, since post-upgrade bytes are raw protocol frames (e.g. WebSocket), not HTTP bodies.

§extensions: RequestExtensions

Type-safe request-scoped extension container. Swapped into each HttpFilterContext and written back after filter execution, following the same lifecycle as filter_metadata.

§filter_metadata: HashMap<String, String>

Durable per-request metadata that persists across all lifecycle phases. Swapped into each HttpFilterContext and written back after filter execution.

§pre_read_mutations: Vec<TrustedHeaderMutation>

Ordered log of trusted header mutations from pre-read body processing. Swapped into each HttpFilterContext and written back after filter execution.

§structured_metadata: HashMap<String, Value>

Structured per-request metadata keyed by namespace. Swapped into each HttpFilterContext and written back after filter execution.

§mutated_request_body_len: Option<usize>

Post-mutation request body length produced during StreamBuffer pre-read.

Stored so upstream_request_filter can repair request framing before Pingora sends headers to the backend.

§pinned_pipeline: Option<Arc<FilterPipeline>>

Pipeline pinned for this request’s entire lifecycle.

Set once during request_filter by cloning the Arc from the listener’s ArcSwap. All subsequent hooks (request body, response, response body, logging) use this reference instead of re-loading from the ArcSwap, ensuring that a hot configuration reload cannot change the pipeline mid-request.

§filter_results: HashMap<&'static str, FilterResultSet>

Filter results from body pre-read. Carried into the next HttpFilterContext so that branch chains attached to the first on_request filter can evaluate body-derived results.

§filter_state: HashMap<usize, Box<dyn Any + Send + Sync>>

Typed per-filter state that persists across all lifecycle phases. Keyed by stable filter invocation ID, unique within the request’s pinned FilterPipeline. Swapped into each HttpFilterContext and written back after filter execution, following the same pattern as filter_metadata.

§metrics_cluster: Option<Arc<str>>

Cluster name snapshot retained for metrics emission in the logging() hook, after cluster has been consumed by filter context construction.

§metrics_cluster_shared: Option<SharedString>

Pre-built SharedString for the metrics cluster label.

Cached when metrics_cluster is set so that emit_request_metrics avoids an Arc clone per request.

§metrics_route: Option<SharedString>

Matched route path-match pattern for the route metric label.

§upstream_connect_start: Option<Instant>

When the current upstream connect attempt started.

§pre_read_body: Option<VecDeque<Bytes>>

Pre-read body chunks (StreamBuffer mode). When StreamBuffer is active, the body is read during request_filter (before upstream selection) so that body-based routing can influence upstream_peer. The request_body_filter hook then forwards these stored chunks instead of reading from the session.

Uses VecDeque so that draining from the front is O(1).

§request_body_buffer: Option<BodyBuffer>

Buffer for request body accumulation in StreamBuffer mode.

§request_body_bytes: u64

Accumulated request body bytes seen so far.

§request_body_mode: BodyMode

Per-request body delivery mode for the request direction. Seeded from static pipeline capabilities, then potentially upgraded by filters during on_request.

§request_body_released: bool

Whether the request body has been released (StreamBuffer mode). Once true, remaining chunks bypass buffering and stream through.

§request_is_idempotent: bool

Whether the request method is idempotent (GET, HEAD, OPTIONS).

§request_snapshot: Option<Request>

Snapshot of the original request for body/response body phases.

§request_span: Span

Root tracing span for this request’s lifecycle.

Created during request_filter with OpenTelemetry HTTP semantic convention attributes. Response-phase attributes (http.response.status_code, upstream.address, upstream.cluster) are recorded in the logging hook before the span is dropped.

§request_start: Instant

When this request was received.

§response_body_buffer: Option<BodyBuffer>

Buffer for response body accumulation in StreamBuffer mode.

§response_body_bytes: u64

Accumulated response body bytes seen so far.

§response_body_mode: BodyMode

Per-request body delivery mode for the response direction. Seeded from static pipeline capabilities, then potentially upgraded by filters during on_response.

§response_body_released: bool

Whether the response body has been released (StreamBuffer mode).

§response_header_snapshot: Option<Response>

Snapshot of response headers after response-phase filters.

Used to evaluate response_conditions consistently during response-body hooks, where Pingora no longer exposes mutable response headers.

§upstream_response_status: Option<u16>

Upstream response status code, captured during response_filter for passive health recording in the logging hook.

§response_phase_done: bool

Whether the response phase has been executed. Used to ensure cleanup (e.g. least-connections counter release) in the logging() hook when errors bypass response_filter.

§retries: u32

Number of upstream connection retries attempted.

§selected_endpoint_index: Option<usize>

Index of the selected endpoint in the cluster’s endpoint list. Set during load balancing; used for passive health recording in the logging hook.

§rewritten_path: Option<String>

Rewritten URI path for the upstream request.

Set by the path_rewrite filter via HttpFilterContext and applied in upstream_request_filter.

§upstream: Option<Upstream>

Upstream endpoint selected by the load balancer filter.

§upstream_for_retry: Option<Upstream>

Saved upstream for retry (cloned before first use).

Implementations§

Source§

impl PingoraRequestCtx

Source

pub fn build_filter_context<'a>( &mut self, pipeline: &'a FilterPipeline, request: &'a Request, response_header: Option<&'a mut Response>, ) -> HttpFilterContext<'a>

Build an HttpFilterContext using an external request reference.

Takes cluster and upstream from self (leaving None behind) so that filters can reassign them. The caller must write those fields back after filter execution.

use praxis_filter::{FilterPipeline, FilterRegistry, Request};
use praxis_protocol::http::pingora::context::PingoraRequestCtx;

let registry = FilterRegistry::with_builtins();
let pipeline = FilterPipeline::build(&mut [], &registry).unwrap();
let request = Request {
    method: http::Method::GET,
    uri: http::Uri::from_static("/"),
    headers: http::HeaderMap::new(),
};
let mut ctx = PingoraRequestCtx::default();
let filter_ctx = ctx.build_filter_context(&pipeline, &request, None);
assert!(filter_ctx.cluster.is_none());
Source

pub fn filter_context_for<'a>( &'a mut self, pipeline: &'a FilterPipeline, response_header: Option<&'a mut Response>, ) -> Option<HttpFilterContext<'a>>

Build an HttpFilterContext from the stored request_snapshot.

Uses disjoint field borrowing so that request_snapshot is borrowed immutably while cluster and upstream are taken mutably.

Returns None when request_snapshot is not set.

use praxis_filter::{FilterPipeline, FilterRegistry, Request};
use praxis_protocol::http::pingora::context::PingoraRequestCtx;

let registry = FilterRegistry::with_builtins();
let pipeline = FilterPipeline::build(&mut [], &registry).unwrap();
let mut ctx = PingoraRequestCtx::default();
ctx.request_snapshot = Some(Request {
    method: http::Method::GET,
    uri: http::Uri::from_static("/"),
    headers: http::HeaderMap::new(),
});
let filter_ctx = ctx.filter_context_for(&pipeline, None);
assert!(filter_ctx.is_some());
Source

pub fn response_body_context_for<'a>( &'a mut self, pipeline: &'a FilterPipeline, ) -> Option<(HttpFilterContext<'a>, Option<&'a Response>)>

Build an HttpFilterContext plus the saved response header for body conditions.

Response body hooks do not receive mutable headers, but their response_conditions still need the response status and headers captured during the response phase.

Source

pub fn pin_pipeline( &mut self, swap: &ArcSwap<FilterPipeline>, ) -> Arc<FilterPipeline> ⓘ

Pin the current pipeline for this request’s entire lifecycle.

Clones the Arc from the ArcSwap and stores it in pinned_pipeline. All subsequent hooks should call pipeline instead of re-loading from the ArcSwap.

Called once by request_filter in both body-capable and no-body handlers.

Source

pub fn pipeline(&self, swap: &ArcSwap<FilterPipeline>) -> Arc<FilterPipeline> ⓘ

Return the pinned pipeline, falling back to a fresh ArcSwap load when no pipeline was pinned.

The fallback covers early-failure paths where a lifecycle hook runs before request_filter (e.g. after early_request_filter rejection triggers logging).

Per-body-chunk hooks (request_body_filter, response_body_filter) call this on every chunk, incurring one Arc::clone per invocation.

Trait Implementations§

Source§

impl Default for PingoraRequestCtx

Source§

fn default() -> Self

Returns the “default value” for a type. Read more

Auto Trait Implementations§

Blanket Implementations§

Source§

impl<T> Any for T
where T: 'static + ?Sized,

Source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
Source§

impl<'a, T, E> AsTaggedExplicit<'a, E> for T
where T: 'a,

Source§

fn explicit(self, class: Class, tag: u32) -> TaggedParser<'a, Explicit, Self, E>

Source§

impl<'a, T, E> AsTaggedImplicit<'a, E> for T
where T: 'a,

Source§

fn implicit( self, class: Class, constructed: bool, tag: u32, ) -> TaggedParser<'a, Implicit, Self, E>

Source§

impl<T> Borrow<T> for T
where T: ?Sized,

Source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
Source§

impl<T> BorrowMut<T> for T
where T: ?Sized,

Source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
Source§

impl<ST, DT> CastableFrom<ST, Initialized, Initialized> for DT
where ST: ?Sized, DT: ?Sized,

Source§

impl<ST, DT> CastableFrom<ST, Uninit, Uninit> for DT
where ST: ?Sized, DT: ?Sized,

Source§

impl<T> From<T> for T

Source§

fn from(t: T) -> T

Returns the argument unchanged.

Source§

impl<T> Instrument for T

Source§

fn instrument(self, span: Span) -> Instrumented<Self> ⓘ

Instruments this type with the provided Span, returning an Instrumented wrapper. Read more
Source§

fn in_current_span(self) -> Instrumented<Self> ⓘ

Instruments this type with the current Span, returning an Instrumented wrapper. Read more
Source§

impl<T, U> Into<U> for T
where U: From<T>,

Source§

fn into(self) -> U

Calls U::from(self).

That is, this conversion is whatever the implementation of From<T> for U chooses to do.

Source§

impl<T> Pointable for T

Source§

const ALIGN: usize

The alignment of pointer.
Source§

type Init = T

The type for initializers.
Source§

unsafe fn init(init: <T as Pointable>::Init) -> usize

Initializes a with the given initializer. Read more
Source§

unsafe fn deref<'a>(ptr: usize) -> &'a T

Dereferences the given pointer. Read more
Source§

unsafe fn deref_mut<'a>(ptr: usize) -> &'a mut T

Mutably dereferences the given pointer. Read more
Source§

unsafe fn drop(ptr: usize)

Drops the object pointed to by the given pointer. Read more
Source§

impl<T> Read<Exclusive, BecauseExclusive> for T
where T: ?Sized,

Source§

impl<T> Same for T

Source§

type Output = T

Should always be Self
Source§

impl<T, U> TryFrom<U> for T
where U: Into<T>,

Source§

type Error = Infallible

The type returned in the event of a conversion error.
Source§

fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error>

Performs the conversion.
Source§

impl<T, U> TryInto<U> for T
where U: TryFrom<T>,

Source§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
Source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.
Source§

impl<V, T> VZip<V> for T
where V: MultiLane<T>,

Source§

fn vzip(self) -> V

Source§

impl<T> WithSubscriber for T

Source§

fn with_subscriber<S>(self, subscriber: S) -> WithDispatch<Self> ⓘ
where S: Into<Dispatch>,

Attaches the provided Subscriber to this type, returning a WithDispatch wrapper. Read more
Source§

fn with_current_subscriber(self) -> WithDispatch<Self> ⓘ

Attaches the current default Subscriber to this type, returning a WithDispatch wrapper. Read more