pub struct PingoraRequestCtx {Show 56 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<Arc<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 retained_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 upstream_exchange_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 pending_rejection: Option<Rejection>,
pub response_delivery_complete: bool,
pub retries: u32,
pub selected_endpoint_index: Option<usize>,
pub attempted_endpoints: Vec<Arc<str>>,
pub retry_policy: Option<Arc<RetryPolicy>>,
pub route_retry_policy: Option<Arc<RetryPolicy>>,
pub cluster_retry_state: Option<Arc<ClusterRetryState>>,
pub cluster_retry_state_released: bool,
pub endpoint_reselector: Option<Arc<EndpointReselector>>,
pub pending_backoff: Option<Duration>,
pub reselect_on_retry: bool,
pub rewritten_path: Option<String>,
pub upstream: Option<Upstream>,
pub upstream_for_retry: Option<Upstream>,
pub upstream_contacted: bool,
/* 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 request’s lifetime; released on drop, 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.
cached_executed_filter_indices: Vec<bool>Cached per-filter execution indices. Same lifecycle as
cached_body_done_indices.
downstream_tls: boolWhether the downstream connection uses TLS.
Set 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<Arc<TlsPeerIdentity>>Verified downstream TLS peer identity.
Set once in request_filter before the first filter runs.
Shared via Arc with 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: boolWhether 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: RequestExtensionsType-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.
Pre-built SharedString for the metrics cluster label.
Cached when metrics_cluster is set.
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.
retained_pre_read_body: Option<VecDeque<Bytes>>Retained copy of the mutated pre-read body for retry replay.
The first attempt drains pre_read_body as it forwards the mutated
body. A retry replays from Pingora’s fixed retry buffer, which holds the
ORIGINAL (pre-mutation) bytes, while apply_mutated_content_length
re-stamps the mutated length. This retained copy re-seeds pre_read_body
on each retry so the replayed body matches the stamped Content-Length,
closing a request-smuggling mismatch. Set only when a body writer ran.
request_body_buffer: Option<BodyBuffer>Buffer for request body accumulation in StreamBuffer mode.
request_body_bytes: u64Accumulated request body bytes seen so far.
request_body_mode: BodyModePer-request body delivery mode for the request direction.
Seeded from static pipeline capabilities, then potentially
upgraded by filters during on_request.
request_body_released: boolWhether the request body has been released (StreamBuffer mode).
Once true, remaining chunks bypass buffering and stream through.
request_is_idempotent: boolWhether the request method is idempotent (GET, HEAD, OPTIONS).
request_snapshot: Option<Request>Snapshot of the original request for body/response body phases.
request_span: SpanRoot tracing span for this request’s lifecycle.
Created during request_filter with OpenTelemetry HTTP semantic
convention attributes. Response-phase attributes
(http.response.status_code, http.route, error.type,
upstream.address, upstream.cluster) are recorded in the
logging hook before the span is dropped.
upstream_exchange_span: SpanChild span covering upstream request/response exchange.
Created in connected_to_upstream after the connection is
established (or reused). Response-phase attributes
(http.response.status_code, http.response.body.size) are
recorded in the logging hook before the span is dropped.
request_start: InstantWhen this request was received.
response_body_buffer: Option<BodyBuffer>Buffer for response body accumulation in StreamBuffer mode.
response_body_bytes: u64Accumulated response body bytes seen so far.
response_body_mode: BodyModePer-request body delivery mode for the response direction.
Seeded from static pipeline capabilities, then potentially
upgraded by filters during on_response.
response_body_released: boolWhether 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: boolWhether 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.
pending_rejection: Option<Rejection>Rejection raised during the response phase, carried across the
Pingora error boundary so fail_to_proxy can deliver its full
configured headers and body instead of a bare status envelope.
response_delivery_complete: boolWhether the response was delivered to completion: a bodyless
response finished its response phase, or the response body
reached end-of-stream. When still false in the logging()
hook, the request ended early (rejection, upstream failure, or
aborted stream) and a fallback access record is emitted.
retries: u32Number 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.
attempted_endpoints: Vec<Arc<str>>Endpoints already attempted (for alternate-host retry).
retry_policy: Option<Arc<RetryPolicy>>Snapshot of the resolved retry policy for this request.
route_retry_policy: Option<Arc<RetryPolicy>>Optional route-level retry policy override (merged by the load balancer).
cluster_retry_state: Option<Arc<ClusterRetryState>>Shared cluster retry state (budget + active requests).
cluster_retry_state_released: boolWhether cluster_retry_state.leave() has already been called.
endpoint_reselector: Option<Arc<EndpointReselector>>Reselector for alternate-host selection on retry.
pending_backoff: Option<Duration>Pending backoff delay to apply before the next upstream_peer call.
reselect_on_retry: boolWhether the next upstream attempt should re-select (alternate host).
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).
upstream_contacted: boolWhether the upstream was contacted (a peer was resolved for at least
one attempt) during this request. Unlike upstream_for_retry, which a
retry decision clears to force reselection, this stays set once the
upstream has been reached, so response-phase health accounting (passive
health, circuit breaker) can tell a genuine connect/read failure from a
request that never reached the cluster. Reset per request.
Implementations§
Source§impl PingoraRequestCtx
impl PingoraRequestCtx
Sourcepub fn build_filter_context<'a>(
&mut self,
pipeline: &'a FilterPipeline,
request: &'a Request,
response_header: Option<&'a mut Response>,
) -> HttpFilterContext<'a>
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 [], ®istry).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());Sourcepub fn filter_context_for<'a>(
&'a mut self,
pipeline: &'a FilterPipeline,
response_header: Option<&'a mut Response>,
) -> Option<HttpFilterContext<'a>>
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.
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 [], ®istry).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());Sourcepub fn response_body_context_for<'a>(
&'a mut self,
pipeline: &'a FilterPipeline,
) -> Option<(HttpFilterContext<'a>, Option<&'a Response>)>
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.
Sourcepub fn pin_pipeline(
&mut self,
swap: &ArcSwap<FilterPipeline>,
) -> Arc<FilterPipeline> ⓘ
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 by early_request_filter before compression negotiation;
repeated calls in later hooks reuse the same generation.
Sourcepub fn pipeline(&self, swap: &ArcSwap<FilterPipeline>) -> Arc<FilterPipeline> ⓘ
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§
Auto Trait Implementations§
impl !Freeze for PingoraRequestCtx
impl !RefUnwindSafe for PingoraRequestCtx
impl !UnwindSafe for PingoraRequestCtx
impl Send for PingoraRequestCtx
impl Sync for PingoraRequestCtx
impl Unpin for PingoraRequestCtx
impl UnsafeUnpin for PingoraRequestCtx
Blanket Implementations§
Source§impl<T> AnyExt for T
impl<T> AnyExt for T
Source§fn downcast_ref<T>(this: &Self) -> Option<&T>where
T: Any,
fn downcast_ref<T>(this: &Self) -> Option<&T>where
T: Any,
T behind referenceSource§fn downcast_mut<T>(this: &mut Self) -> Option<&mut T>where
T: Any,
fn downcast_mut<T>(this: &mut Self) -> Option<&mut T>where
T: Any,
T behind mutable referenceSource§fn downcast_rc<T>(this: Rc<Self>) -> Result<Rc<T>, Rc<Self>>where
T: Any,
fn downcast_rc<T>(this: Rc<Self>) -> Result<Rc<T>, Rc<Self>>where
T: Any,
T behind Rc pointerSource§fn downcast_arc<T>(this: Arc<Self>) -> Result<Arc<T>, Arc<Self>>where
T: Any,
fn downcast_arc<T>(this: Arc<Self>) -> Result<Arc<T>, Arc<Self>>where
T: Any,
T behind Arc pointerSource§impl<'a, T, E> AsTaggedExplicit<'a, E> for Twhere
T: 'a,
impl<'a, T, E> AsTaggedExplicit<'a, E> for Twhere
T: 'a,
Source§impl<'a, T, E> AsTaggedImplicit<'a, E> for Twhere
T: 'a,
impl<'a, T, E> AsTaggedImplicit<'a, E> for Twhere
T: 'a,
Source§impl<T> BorrowMut<T> for Twhere
T: ?Sized,
impl<T> BorrowMut<T> for Twhere
T: ?Sized,
Source§fn borrow_mut(&mut self) -> &mut T
fn borrow_mut(&mut self) -> &mut T
impl<ST, DT> CastableFrom<ST, Initialized, Initialized> for DT
impl<ST, DT> CastableFrom<ST, Uninit, Uninit> for DT
Source§impl<T, X> CoerceTo<T> for Xwhere
T: CoerceFrom<X> + ?Sized,
impl<T, X> CoerceTo<T> for Xwhere
T: CoerceFrom<X> + ?Sized,
fn coerce_rc_to(self: Rc<X>) -> Rc<T>
fn coerce_box_to(self: Box<X>) -> Box<T>
fn coerce_ref_to(&self) -> &T
fn coerce_mut_to(&mut self) -> &mut T
Source§impl<T> Instrument for T
impl<T> Instrument for T
Source§fn instrument(self, span: Span) -> Instrumented<Self> ⓘ
fn instrument(self, span: Span) -> Instrumented<Self> ⓘ
Source§fn in_current_span(self) -> Instrumented<Self> ⓘ
fn in_current_span(self) -> Instrumented<Self> ⓘ
Source§impl<T> IntoEither for T
impl<T> IntoEither for T
Source§fn into_either(self, into_left: bool) -> Either<Self, Self> ⓘ
fn into_either(self, into_left: bool) -> Either<Self, Self> ⓘ
self into a Left variant of Either<Self, Self>
if into_left is true.
Converts self into a Right variant of Either<Self, Self>
otherwise. Read moreSource§fn into_either_with<F>(self, into_left: F) -> Either<Self, Self> ⓘ
fn into_either_with<F>(self, into_left: F) -> Either<Self, Self> ⓘ
self into a Left variant of Either<Self, Self>
if into_left(&self) returns true.
Converts self into a Right variant of Either<Self, Self>
otherwise. Read more