pub struct PingoraRequestCtx {Show 54 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 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>,
/* 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: boolWhether 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<Arc<TlsPeerIdentity>>Verified downstream TLS peer identity.
Set once from the SSL digest in request_filter before
the first filter runs. Shared via Arc with each
HttpFilterContext (an Arc clone per phase, not a deep
copy per body chunk) 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 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: 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).
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.
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 [], ®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 once by request_filter in both body-capable and
no-body handlers.
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.